mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
Issue MoonchildProductions/UXP#1578 - Add global menubar support for GTK
This commit is contained in:
parent
cd1c94480d
commit
564f1026d5
32 changed files with 4811 additions and 4 deletions
634
widget/gtk/nsMenuObject.cpp
Normal file
634
widget/gtk/nsMenuObject.cpp
Normal file
|
|
@ -0,0 +1,634 @@
|
|||
/* 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 "ImageOps.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "imgLoader.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsImageToPixbuf.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#include "nsMenuContainer.h"
|
||||
#include "nsNativeMenuAtoms.h"
|
||||
#include "nsNativeMenuDocListener.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <glib-object.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
#include "nsMenuObject.h"
|
||||
|
||||
// X11's None clashes with StyleDisplay::None
|
||||
#include "X11UndefineNone.h"
|
||||
|
||||
#undef None
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::image::ImageOps;
|
||||
|
||||
#define MAX_WIDTH 350000
|
||||
|
||||
const char* gPropertyStrings[] = {
|
||||
#define DBUSMENU_PROPERTY(e, s, b) s,
|
||||
DBUSMENU_PROPERTIES
|
||||
#undef DBUSMENU_PROPERTY
|
||||
nullptr
|
||||
};
|
||||
|
||||
nsWeakMenuObject* nsWeakMenuObject::sHead;
|
||||
PangoLayout* gPangoLayout = nullptr;
|
||||
|
||||
class nsMenuObjectIconLoader final : public imgINotificationObserver {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGINOTIFICATIONOBSERVER
|
||||
|
||||
nsMenuObjectIconLoader(nsMenuObject* aOwner) : mOwner(aOwner) { };
|
||||
|
||||
void LoadIcon(nsStyleContext* aStyleContext);
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
~nsMenuObjectIconLoader() { };
|
||||
|
||||
nsMenuObject* mOwner;
|
||||
RefPtr<imgRequestProxy> mImageRequest;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsIntRect mImageRect;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMenuObjectIconLoader, imgINotificationObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuObjectIconLoader::Notify(imgIRequest* aProxy,
|
||||
int32_t aType, const nsIntRect* aRect) {
|
||||
if (!mOwner) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aProxy != mImageRequest) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
|
||||
uint32_t status = imgIRequest::STATUS_ERROR;
|
||||
if (NS_FAILED(mImageRequest->GetImageStatus(&status)) ||
|
||||
(status & imgIRequest::STATUS_ERROR)) {
|
||||
mImageRequest->Cancel(NS_BINDING_ABORTED);
|
||||
mImageRequest = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
mImageRequest->GetImage(getter_AddRefs(image));
|
||||
MOZ_ASSERT(image);
|
||||
|
||||
// Ask the image to decode at its intrinsic size.
|
||||
int32_t width = 0, height = 0;
|
||||
image->GetWidth(&width);
|
||||
image->GetHeight(&height);
|
||||
image->RequestDecodeForSize(nsIntSize(width, height), imgIContainer::FLAG_NONE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
||||
mImageRequest->Cancel(NS_BINDING_ABORTED);
|
||||
mImageRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aType != imgINotificationObserver::FRAME_COMPLETE) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIContainer> img;
|
||||
mImageRequest->GetImage(getter_AddRefs(img));
|
||||
if (!img) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mImageRect.IsEmpty()) {
|
||||
img = ImageOps::Clip(img, mImageRect);
|
||||
}
|
||||
|
||||
int32_t width, height;
|
||||
img->GetWidth(&width);
|
||||
img->GetHeight(&height);
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
mOwner->ClearIcon();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (width > 100 || height > 100) {
|
||||
// The icon data needs to go across DBus. Make sure the icon
|
||||
// data isn't too large, else our connection gets terminated and
|
||||
// GDbus helpfully aborts the application. Thank you :)
|
||||
NS_WARNING("Icon data too large");
|
||||
mOwner->ClearIcon();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(img);
|
||||
if (pixbuf) {
|
||||
dbusmenu_menuitem_property_set_image(mOwner->GetNativeData(),
|
||||
DBUSMENU_MENUITEM_PROP_ICON_DATA,
|
||||
pixbuf);
|
||||
g_object_unref(pixbuf);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObjectIconLoader::LoadIcon(nsStyleContext* aStyleContext) {
|
||||
nsIDocument* doc = mOwner->ContentNode()->OwnerDoc();
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsIntRect imageRect;
|
||||
imgRequestProxy* imageRequest = nullptr;
|
||||
|
||||
nsAutoString uriString;
|
||||
if (mOwner->ContentNode()->GetAttr(kNameSpaceID_None, nsGkAtoms::image,
|
||||
uriString)) {
|
||||
NS_NewURI(getter_AddRefs(uri), uriString);
|
||||
} else {
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsPresContext* pc = shell->GetPresContext();
|
||||
if (!pc || !aStyleContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsStyleList* list = aStyleContext->StyleList();
|
||||
imageRequest = list->GetListStyleImage();
|
||||
if (imageRequest) {
|
||||
imageRequest->GetURI(getter_AddRefs(uri));
|
||||
imageRect = list->mImageRegion.ToNearestPixels(
|
||||
pc->AppUnitsPerDevPixel());
|
||||
}
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
mOwner->ClearIcon();
|
||||
mURI = nullptr;
|
||||
|
||||
if (mImageRequest) {
|
||||
mImageRequest->Cancel(NS_BINDING_ABORTED);
|
||||
mImageRequest = nullptr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool same;
|
||||
if (mURI && NS_SUCCEEDED(mURI->Equals(uri, &same)) && same &&
|
||||
(!imageRequest || imageRect == mImageRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mImageRequest) {
|
||||
mImageRequest->Cancel(NS_BINDING_ABORTED);
|
||||
mImageRequest = nullptr;
|
||||
}
|
||||
|
||||
mURI = uri;
|
||||
|
||||
if (imageRequest) {
|
||||
mImageRect = imageRect;
|
||||
imageRequest->Clone(this, getter_AddRefs(mImageRequest));
|
||||
} else {
|
||||
mImageRect.SetEmpty();
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
|
||||
RefPtr<imgLoader> loader =
|
||||
nsContentUtils::GetImgLoaderForDocument(doc);
|
||||
if (!loader || !loadGroup) {
|
||||
NS_WARNING("Failed to get loader or load group for image load");
|
||||
return;
|
||||
}
|
||||
|
||||
loader->LoadImage(uri, nullptr, nullptr, mozilla::net::RP_Unset,
|
||||
nullptr, loadGroup, this, nullptr, nullptr,
|
||||
nsIRequest::LOAD_NORMAL, nullptr,
|
||||
nsIContentPolicy::TYPE_IMAGE, EmptyString(),
|
||||
getter_AddRefs(mImageRequest));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObjectIconLoader::Destroy() {
|
||||
if (mImageRequest) {
|
||||
mImageRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
||||
mImageRequest = nullptr;
|
||||
}
|
||||
|
||||
mOwner = nullptr;
|
||||
}
|
||||
|
||||
static int
|
||||
CalculateTextWidth(const nsAString& aText) {
|
||||
if (!gPangoLayout) {
|
||||
PangoFontMap* fontmap = pango_cairo_font_map_get_default();
|
||||
PangoContext* ctx = pango_font_map_create_context(fontmap);
|
||||
gPangoLayout = pango_layout_new(ctx);
|
||||
g_object_unref(ctx);
|
||||
}
|
||||
|
||||
pango_layout_set_text(gPangoLayout, NS_ConvertUTF16toUTF8(aText).get(), -1);
|
||||
|
||||
int width, dummy;
|
||||
pango_layout_get_size(gPangoLayout, &width, &dummy);
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
static const nsDependentString
|
||||
GetEllipsis() {
|
||||
static char16_t sBuf[4] = { 0, 0, 0, 0 };
|
||||
if (!sBuf[0]) {
|
||||
nsAdoptingString ellipsis = Preferences::GetLocalizedString("intl.ellipsis");
|
||||
if (!ellipsis.IsEmpty()) {
|
||||
uint32_t l = ellipsis.Length();
|
||||
const nsAdoptingString::char_type* c = ellipsis.BeginReading();
|
||||
uint32_t i = 0;
|
||||
while (i < 3 && i < l) {
|
||||
sBuf[i++] =* (c++);
|
||||
}
|
||||
} else {
|
||||
sBuf[0] = '.';
|
||||
sBuf[1] = '.';
|
||||
sBuf[2] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
return nsDependentString(sBuf);
|
||||
}
|
||||
|
||||
static int
|
||||
GetEllipsisWidth() {
|
||||
static int sEllipsisWidth = -1;
|
||||
|
||||
if (sEllipsisWidth == -1) {
|
||||
sEllipsisWidth = CalculateTextWidth(GetEllipsis());
|
||||
}
|
||||
|
||||
return sEllipsisWidth;
|
||||
}
|
||||
|
||||
nsMenuObject::nsMenuObject(nsMenuContainer* aParent, nsIContent* aContent) :
|
||||
mContent(aContent),
|
||||
mListener(aParent->DocListener()),
|
||||
mParent(aParent),
|
||||
mNativeData(nullptr) {
|
||||
MOZ_ASSERT(mContent);
|
||||
MOZ_ASSERT(mListener);
|
||||
MOZ_ASSERT(mParent);
|
||||
}
|
||||
|
||||
nsMenuObject::nsMenuObject(nsNativeMenuDocListener* aListener,
|
||||
nsIContent* aContent) :
|
||||
mContent(aContent),
|
||||
mListener(aListener),
|
||||
mParent(nullptr),
|
||||
mNativeData(nullptr) {
|
||||
MOZ_ASSERT(mContent);
|
||||
MOZ_ASSERT(mListener);
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::UpdateLabel() {
|
||||
// Goanna stores the label and access key in separate attributes
|
||||
// so we need to convert label="Foo_Bar"/accesskey="F" in to
|
||||
// label="_Foo__Bar" for dbusmenu
|
||||
|
||||
nsAutoString label;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label);
|
||||
|
||||
nsAutoString accesskey;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accesskey);
|
||||
|
||||
const nsAutoString::char_type* akey = accesskey.BeginReading();
|
||||
char16_t keyLower = ToLowerCase(*akey);
|
||||
char16_t keyUpper = ToUpperCase(*akey);
|
||||
|
||||
const nsAutoString::char_type* iter = label.BeginReading();
|
||||
const nsAutoString::char_type* end = label.EndReading();
|
||||
uint32_t length = label.Length();
|
||||
uint32_t pos = 0;
|
||||
bool foundAccessKey = false;
|
||||
|
||||
while (iter != end) {
|
||||
if (*iter != char16_t('_')) {
|
||||
if ((*iter != keyLower &&* iter != keyUpper) || foundAccessKey) {
|
||||
++iter;
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
foundAccessKey = true;
|
||||
}
|
||||
|
||||
label.SetLength(++length);
|
||||
|
||||
iter = label.BeginReading() + pos;
|
||||
end = label.EndReading();
|
||||
nsAutoString::char_type* cur = label.BeginWriting() + pos;
|
||||
|
||||
memmove(cur + 1, cur, (length - 1 - pos)* sizeof(nsAutoString::char_type));
|
||||
* cur = nsAutoString::char_type('_');
|
||||
|
||||
iter += 2;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if (CalculateTextWidth(label) <= MAX_WIDTH) {
|
||||
dbusmenu_menuitem_property_set(mNativeData,
|
||||
DBUSMENU_MENUITEM_PROP_LABEL,
|
||||
NS_ConvertUTF16toUTF8(label).get());
|
||||
return;
|
||||
}
|
||||
|
||||
// This sucks.
|
||||
// This should be done at the point where the menu is drawn (hello Unity),
|
||||
// but unfortunately it doesn't do that and will happily fill your entire
|
||||
// screen width with a menu if you have a bookmark with a really long title.
|
||||
// This leaves us with no other option but to ellipsize here, with no proper
|
||||
// knowledge of Unity's render path, font size etc. This is better than nothing
|
||||
nsAutoString truncated;
|
||||
int target = MAX_WIDTH - GetEllipsisWidth();
|
||||
length = label.Length();
|
||||
|
||||
static nsIContent::AttrValuesArray strings[] = {
|
||||
&nsGkAtoms::left, &nsGkAtoms::start,
|
||||
&nsGkAtoms::center, &nsGkAtoms::right,
|
||||
&nsGkAtoms::end, nullptr
|
||||
};
|
||||
|
||||
int32_t type = mContent->FindAttrValueIn(kNameSpaceID_None,
|
||||
nsGkAtoms::crop,
|
||||
strings, eCaseMatters);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
case 1:
|
||||
// FIXME: Implement left cropping
|
||||
case 2:
|
||||
// FIXME: Implement center cropping
|
||||
case 3:
|
||||
case 4:
|
||||
default:
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
truncated.Append(label.CharAt(i));
|
||||
if (CalculateTextWidth(truncated) > target) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
truncated.Append(GetEllipsis());
|
||||
}
|
||||
|
||||
dbusmenu_menuitem_property_set(mNativeData,
|
||||
DBUSMENU_MENUITEM_PROP_LABEL,
|
||||
NS_ConvertUTF16toUTF8(truncated).get());
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::UpdateVisibility(nsStyleContext* aStyleContext) {
|
||||
bool vis = true;
|
||||
|
||||
if (aStyleContext &&
|
||||
(aStyleContext->StyleDisplay()->mDisplay == StyleDisplay::None ||
|
||||
aStyleContext->StyleVisibility()->mVisible ==
|
||||
NS_STYLE_VISIBILITY_COLLAPSE)) {
|
||||
vis = false;
|
||||
}
|
||||
|
||||
dbusmenu_menuitem_property_set_bool(mNativeData,
|
||||
DBUSMENU_MENUITEM_PROP_VISIBLE,
|
||||
vis);
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::UpdateSensitivity() {
|
||||
bool disabled = mContent->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
dbusmenu_menuitem_property_set_bool(mNativeData,
|
||||
DBUSMENU_MENUITEM_PROP_ENABLED,
|
||||
!disabled);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::UpdateIcon(nsStyleContext* aStyleContext) {
|
||||
if (ShouldShowIcon()) {
|
||||
if (!mIconLoader) {
|
||||
mIconLoader = new nsMenuObjectIconLoader(this);
|
||||
}
|
||||
|
||||
mIconLoader->LoadIcon(aStyleContext);
|
||||
} else {
|
||||
if (mIconLoader) {
|
||||
mIconLoader->Destroy();
|
||||
mIconLoader = nullptr;
|
||||
}
|
||||
|
||||
ClearIcon();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
nsMenuObject::GetStyleContext() {
|
||||
nsIPresShell* shell = mContent->OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsStyleContext> sc =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(
|
||||
mContent->AsElement(), nullptr, shell);
|
||||
|
||||
return sc.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::InitializeNativeData() {
|
||||
}
|
||||
|
||||
nsMenuObject::PropertyFlags
|
||||
nsMenuObject::SupportedProperties() const {
|
||||
return static_cast<nsMenuObject::PropertyFlags>(0);
|
||||
}
|
||||
|
||||
bool
|
||||
nsMenuObject::IsCompatibleWithNativeData(DbusmenuMenuitem* aNativeData) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::UpdateContentAttributes() {
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::Update(nsStyleContext* aStyleContext) {
|
||||
}
|
||||
|
||||
bool
|
||||
nsMenuObject::ShouldShowIcon() const {
|
||||
// Ideally we want to know the visibility of the anonymous XUL image in
|
||||
// our menuitem, but this isn't created because we don't have a frame.
|
||||
// The following works by default (because xul.css hides images in menuitems
|
||||
// that don't have the "menuitem-with-favicon" class). It's possible a third
|
||||
// party theme could override this, but, oh well...
|
||||
const nsAttrValue* classes = mContent->AsElement()->GetClasses();
|
||||
if (!classes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < classes->GetAtomCount(); ++i) {
|
||||
if (classes->AtomAt(i) == nsNativeMenuAtoms::menuitem_with_favicon) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::ClearIcon() {
|
||||
dbusmenu_menuitem_property_remove(mNativeData,
|
||||
DBUSMENU_MENUITEM_PROP_ICON_DATA);
|
||||
}
|
||||
|
||||
nsMenuObject::~nsMenuObject() {
|
||||
nsWeakMenuObject::NotifyDestroyed(this);
|
||||
|
||||
if (mIconLoader) {
|
||||
mIconLoader->Destroy();
|
||||
}
|
||||
|
||||
if (mListener) {
|
||||
mListener->UnregisterForContentChanges(mContent);
|
||||
}
|
||||
|
||||
if (mNativeData) {
|
||||
g_object_unref(mNativeData);
|
||||
mNativeData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::CreateNativeData() {
|
||||
MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
|
||||
|
||||
mNativeData = dbusmenu_menuitem_new();
|
||||
InitializeNativeData();
|
||||
if (mParent && mParent->IsBeingDisplayed()) {
|
||||
ContainerIsOpening();
|
||||
}
|
||||
|
||||
mListener->RegisterForContentChanges(mContent, this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMenuObject::AdoptNativeData(DbusmenuMenuitem* aNativeData) {
|
||||
MOZ_ASSERT(mNativeData == nullptr, "This node already has a DbusmenuMenuitem. The old one will be leaked");
|
||||
|
||||
if (!IsCompatibleWithNativeData(aNativeData)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mNativeData = aNativeData;
|
||||
g_object_ref(mNativeData);
|
||||
|
||||
PropertyFlags supported = SupportedProperties();
|
||||
PropertyFlags mask = static_cast<PropertyFlags>(1);
|
||||
|
||||
for (uint32_t i = 0; gPropertyStrings[i]; ++i) {
|
||||
if (!(mask & supported)) {
|
||||
dbusmenu_menuitem_property_remove(mNativeData, gPropertyStrings[i]);
|
||||
}
|
||||
mask = static_cast<PropertyFlags>(mask << 1);
|
||||
}
|
||||
|
||||
InitializeNativeData();
|
||||
if (mParent && mParent->IsBeingDisplayed()) {
|
||||
ContainerIsOpening();
|
||||
}
|
||||
|
||||
mListener->RegisterForContentChanges(mContent, this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuObject::ContainerIsOpening() {
|
||||
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
|
||||
|
||||
UpdateContentAttributes();
|
||||
|
||||
RefPtr<nsStyleContext> sc = GetStyleContext();
|
||||
Update(sc);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsWeakMenuObject::AddWeakReference(nsWeakMenuObject* aWeak) {
|
||||
aWeak->mPrev = sHead;
|
||||
sHead = aWeak;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsWeakMenuObject::RemoveWeakReference(nsWeakMenuObject* aWeak) {
|
||||
if (aWeak == sHead) {
|
||||
sHead = aWeak->mPrev;
|
||||
return;
|
||||
}
|
||||
|
||||
nsWeakMenuObject* weak = sHead;
|
||||
while (weak && weak->mPrev != aWeak) {
|
||||
weak = weak->mPrev;
|
||||
}
|
||||
|
||||
if (weak) {
|
||||
weak->mPrev = aWeak->mPrev;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsWeakMenuObject::NotifyDestroyed(nsMenuObject* aMenuObject) {
|
||||
nsWeakMenuObject* weak = sHead;
|
||||
while (weak) {
|
||||
if (weak->mMenuObject == aMenuObject) {
|
||||
weak->mMenuObject = nullptr;
|
||||
}
|
||||
|
||||
weak = weak->mPrev;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue