nsresult nsXULTooltipListener::FindTooltip(nsIContent* aTarget, nsIContent** aTooltip) { if (!aTarget) return NS_ERROR_NULL_POINTER; // before we go on, make sure that target node still has a window nsCOMPtr<nsIDocument> document = aTarget->GetDocument(); if (!document) { NS_WARNING("Unable to retrieve the tooltip node document."); return NS_ERROR_FAILURE; } nsCOMPtr<nsPIDOMWindow> window = document->GetWindow(); if (!window) { return NS_OK; } PRBool closed; window->GetClosed(&closed); if (closed) { return NS_OK; } nsAutoString tooltipText; aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, tooltipText); if (!tooltipText.IsEmpty()) { // specifying tooltiptext means we will always use the default tooltip nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetPrimaryShell()); NS_ENSURE_STATE(rootBox); *aTooltip = rootBox->GetDefaultTooltip(); if (*aTooltip) { NS_ADDREF(*aTooltip); (*aTooltip)->SetAttr(kNameSpaceID_None, nsGkAtoms::label, tooltipText, PR_TRUE); } return NS_OK; } nsAutoString tooltipId; aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltip, tooltipId); // if tooltip == _child, look for first <tooltip> child if (tooltipId.EqualsLiteral("_child")) { GetImmediateChild(aTarget, nsGkAtoms::tooltip, aTooltip); return NS_OK; } if (!tooltipId.IsEmpty()) { // tooltip must be an id, use getElementById to find it nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document); if (!domDocument) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIDOMElement> tooltipEl; domDocument->GetElementById(tooltipId, getter_AddRefs(tooltipEl)); if (tooltipEl) { #ifdef MOZ_XUL mNeedTitletip = PR_FALSE; #endif CallQueryInterface(tooltipEl, aTooltip); return NS_OK; } } #ifdef MOZ_XUL // titletips should just use the default tooltip if (mIsSourceTree && mNeedTitletip) { nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetPrimaryShell()); NS_ENSURE_STATE(rootBox); NS_IF_ADDREF(*aTooltip = rootBox->GetDefaultTooltip()); } #endif return NS_OK; }
// // LaunchPopup // // Given the element on which the event was triggered and the mouse locations in // Client and widget coordinates, popup a new window showing the appropriate // content. // // aTargetContent is the target of the mouse event aEvent that triggered the // popup. mElement is the element that the popup menu is attached to. // aTargetContent may be equal to mElement or it may be a descendant. // // This looks for an attribute on |mElement| of the appropriate popup type // (popup, context) and uses that attribute's value as an ID for // the popup content in the document. // nsresult nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent) { nsresult rv = NS_OK; nsAutoString type(NS_LITERAL_STRING("popup")); if (mIsContext) type.AssignLiteral("context"); nsAutoString identifier; mElement->GetAttribute(type, identifier); if (identifier.IsEmpty()) { if (type.EqualsLiteral("popup")) mElement->GetAttribute(NS_LITERAL_STRING("menu"), identifier); else if (type.EqualsLiteral("context")) mElement->GetAttribute(NS_LITERAL_STRING("contextmenu"), identifier); if (identifier.IsEmpty()) return rv; } // Try to find the popup content and the document. nsCOMPtr<nsIContent> content = do_QueryInterface(mElement); nsCOMPtr<nsIDocument> document = content->GetDocument(); // Turn the document into a DOM document so we can use getElementById nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document); if (!domDocument) { NS_ERROR("Popup attached to an element that isn't in XUL!"); return NS_ERROR_FAILURE; } // Handle the _child case for popups and context menus nsCOMPtr<nsIDOMElement> popupElement; if (identifier.EqualsLiteral("_child")) { nsCOMPtr<nsIContent> popup; GetImmediateChild(content, nsGkAtoms::menupopup, getter_AddRefs(popup)); if (popup) popupElement = do_QueryInterface(popup); else { nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument)); nsCOMPtr<nsIDOMNodeList> list; nsDoc->GetAnonymousNodes(mElement, getter_AddRefs(list)); if (list) { PRUint32 ctr,listLength; nsCOMPtr<nsIDOMNode> node; list->GetLength(&listLength); for (ctr = 0; ctr < listLength; ctr++) { list->Item(ctr, getter_AddRefs(node)); nsCOMPtr<nsIContent> childContent(do_QueryInterface(node)); if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup, kNameSpaceID_XUL)) { popupElement = do_QueryInterface(childContent); break; } } } } } else if (NS_FAILED(rv = domDocument->GetElementById(identifier, getter_AddRefs(popupElement)))) { // Use getElementById to obtain the popup content and gracefully fail if // we didn't find any popup content in the document. NS_ERROR("GetElementById had some kind of spasm."); return rv; } // return if no popup was found or the popup is the element itself. if ( !popupElement || popupElement == mElement) return NS_OK; // Submenus can't be used as context menus or popups, bug 288763. // Similar code also in nsXULTooltipListener::GetTooltipFor. nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement); nsIContent* parent = popup->GetParent(); if (parent) { nsIFrame* frame = parent->GetPrimaryFrame(); if (frame && frame->GetType() == nsGkAtoms::menuFrame) return NS_OK; } nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (!pm) return NS_OK; // For left-clicks, if the popup has an position attribute, or both the // popupanchor and popupalign attributes are used, anchor the popup to the // element, otherwise just open it at the screen position where the mouse // was clicked. Context menus always open at the mouse position. mPopupContent = popup; if (!mIsContext && (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) || (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) && mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)))) { pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0, PR_FALSE, PR_TRUE, PR_FALSE, aEvent); } else { PRInt32 xPos = 0, yPos = 0; nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent); mouseEvent->GetScreenX(&xPos); mouseEvent->GetScreenY(&yPos); pm->ShowPopupAtScreen(mPopupContent, xPos, yPos, mIsContext, aEvent); } return NS_OK; }