Bug 503943, back out mouse capture patch, CLOSED TREE

This commit is contained in:
Neil Deakin 2009-09-10 12:11:41 -04:00
Родитель ffa602c81b
Коммит cef5702d08
33 изменённых файлов: 646 добавлений и 609 удалений

Просмотреть файл

@ -2773,18 +2773,6 @@ nsDocument::DestroyClassNameArray(void* aData)
delete info;
}
NS_IMETHODIMP
nsDocument::ReleaseCapture()
{
// only release the capture if the caller can access it. This prevents a
// page from stopping a scrollbar grab for example.
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
if (node && nsContentUtils::CanCallerAccess(node)) {
nsIPresShell::SetCapturingContent(nsnull, 0);
}
return NS_OK;
}
nsresult
nsDocument::SetBaseURI(nsIURI* aURI)
{

Просмотреть файл

@ -1084,29 +1084,6 @@ nsNSElementTearoff::GetClassList(nsIDOMDOMTokenList** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsNSElementTearoff::SetCapture(PRBool aRetargetToElement)
{
// If there is already an active capture, ignore this request. This would
// occur if a splitter, frame resizer, etc had already captured and we don't
// want to override those.
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
if (node)
return NS_OK;
nsIPresShell::SetCapturingContent(mContent, aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0);
return NS_OK;
}
NS_IMETHODIMP
nsNSElementTearoff::ReleaseCapture()
{
if (nsIPresShell::GetCapturingContent() == mContent) {
nsIPresShell::SetCapturingContent(nsnull, 0);
}
return NS_OK;
}
//----------------------------------------------------------------------

Просмотреть файл

@ -2741,9 +2741,19 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
{
if (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton &&
!mNormalLMouseEventInProcess) {
// We got a mouseup event while a mousedown event was being processed.
// Make sure that the capturing content is cleared.
nsIPresShell::SetCapturingContent(nsnull, 0);
//Our state is out of whack. We got a mouseup while still processing
//the mousedown. Kill View-level mouse capture or it'll stay stuck
if (aView) {
nsIViewManager* viewMan = aView->GetViewManager();
if (viewMan) {
nsIView* grabbingView;
viewMan->GetMouseEventGrabber(grabbingView);
if (grabbingView == aView) {
PRBool result;
viewMan->GrabMouseEvents(nsnull, result);
}
}
}
break;
}
@ -2848,9 +2858,17 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
ret =
CheckForAndDispatchClick(presContext, (nsMouseEvent*)aEvent, aStatus);
}
nsIPresShell *shell = presContext->GetPresShell();
if (shell) {
nsIViewManager* viewMan = shell->GetViewManager();
if (viewMan) {
nsIView* grabbingView = nsnull;
viewMan->GetMouseEventGrabber(grabbingView);
if (grabbingView == aView) {
PRBool result;
viewMan->GrabMouseEvents(nsnull, result);
}
}
nsCOMPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
frameSelection->SetMouseDownState(PR_FALSE);
}

Просмотреть файл

@ -411,22 +411,15 @@ protected:
static PRInt32 sUserInputEventDepth;
};
/**
* This class is used while processing real user input. During this time, popups
* are allowed. For mousedown events, mouse capturing is also permitted.
*/
class nsAutoHandlingUserInputStatePusher
{
public:
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput, PRBool aIsMouseDown)
: mIsHandlingUserInput(aIsHandlingUserInput), mIsMouseDown(aIsMouseDown)
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput)
: mIsHandlingUserInput(aIsHandlingUserInput)
{
if (aIsHandlingUserInput) {
nsEventStateManager::StartHandlingUserInput();
if (aIsMouseDown) {
nsIPresShell::SetCapturingContent(nsnull, 0);
nsIPresShell::AllowMouseCapture(PR_TRUE);
}
}
}
@ -434,15 +427,11 @@ public:
{
if (mIsHandlingUserInput) {
nsEventStateManager::StopHandlingUserInput();
if (mIsMouseDown) {
nsIPresShell::AllowMouseCapture(PR_FALSE);
}
}
}
protected:
PRBool mIsHandlingUserInput;
PRBool mIsMouseDown;
private:
// Hide so that this class can only be stack-allocated

Просмотреть файл

@ -1139,7 +1139,7 @@ nsHTMLFormElement::SubmitSubmission(nsIFormSubmission* aFormSubmission)
{
nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput);
rv = aFormSubmission->SubmitTo(actionURI, target, this, linkHandler,
getter_AddRefs(docShell),

Просмотреть файл

@ -43,7 +43,7 @@
interface nsIBoxObject;
interface nsIDOMLocation;
[scriptable, uuid(B7E9211B-F29F-4E2D-9762-6BCBC64E5C05)]
[scriptable, uuid(09a439ad-4079-46d5-a050-4d7015d1a108)]
interface nsIDOMNSDocument : nsISupports
{
readonly attribute DOMString characterSet;
@ -91,10 +91,4 @@ interface nsIDOMNSDocument : nsISupports
*/
nsIDOMElement elementFromPoint(in long x, in long y);
/**
* Release the current mouse capture if it is on an element within this
* document.
*/
void releaseCapture();
};

Просмотреть файл

@ -39,7 +39,7 @@
#include "domstubs.idl"
[scriptable, uuid(FA8D7AF8-C208-4564-A0CD-346C345711F0)]
[scriptable, uuid(df86b1a8-02c3-47be-a76b-856620f925df)]
interface nsIDOMNSElement : nsISupports
{
/*
@ -152,20 +152,4 @@ interface nsIDOMNSElement : nsISupports
* Returns a DOMTokenList object reflecting the class attribute.
*/
readonly attribute nsIDOMDOMTokenList classList;
/**
* Set this during a mousedown event to grab and retarget all mouse events
* to this element until the mouse button is released or releaseCapture is
* called. If retargetToElement is true, then all events are targetted at
* this element. If false, events can also fire at descendants of this
* element.
*
*/
void setCapture([optional] in boolean retargetToElement);
/**
* If this element has captured the mouse, release the capture. If another
* element has captured the mouse, this method has no effect.
*/
void releaseCapture();
};

Просмотреть файл

@ -104,23 +104,6 @@ class nsDisplayListBuilder;
typedef short SelectionType;
typedef PRUint32 nsFrameState;
// Flags to pass to SetCapturingContent
//
// when assigning capture, ignore whether capture is allowed or not
#define CAPTURE_IGNOREALLOWED 1
// true if events should be targeted at the capturing content or its children
#define CAPTURE_RETARGETTOELEMENT 2
typedef struct CapturingContentInfo {
// capture should only be allowed during a mousedown event
PRPackedBool mAllowed;
PRPackedBool mRetargetToElement;
nsIContent* mContent;
CapturingContentInfo() :
mAllowed(PR_FALSE), mRetargetToElement(PR_FALSE), mContent(nsnull) { }
} CapturingContentInfo;
// eba51d41-68db-4dab-a57b-dc1a2704de87
#define NS_IPRESSHELL_IID \
{ 0xeba51d41, 0x68db, 0x4dab, \
@ -873,42 +856,6 @@ public:
return mObservesMutationsForPrint;
}
// mouse capturing
static CapturingContentInfo gCaptureInfo;
/**
* When capturing content is set, it traps all mouse events and retargets
* them at this content node. If capturing is not allowed
* (gCaptureInfo.mAllowed is false), then capturing is not set. However, if
* the CAPTURE_IGNOREALLOWED flag is set, the allowed state is ignored and
* capturing is set regardless. To disable capture, pass null for the value
* of aContent.
*
* If CAPTURE_RETARGETTOELEMENT is set, all mouse events are targeted at
* aContent only. Otherwise, mouse events are targeted at aContent or its
* descendants. That is, descendants of aContent receive mouse events as
* they normally would, but mouse events outside of aContent are retargeted
* to aContent.
*/
static void SetCapturingContent(nsIContent* aContent, PRUint8 aFlags);
/**
* Return the active content currently capturing the mouse if any.
*/
static nsIContent* GetCapturingContent()
{
return gCaptureInfo.mContent;
}
/**
* Allow or disallow mouse capturing.
*/
static void AllowMouseCapture(PRBool aAllowed)
{
gCaptureInfo.mAllowed = aAllowed;
}
protected:
// IMPORTANT: The ownership implicit in the following member variables
// has been explicitly checked. If you add any members to this class,

Просмотреть файл

@ -208,7 +208,6 @@ static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID);
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE;
CapturingContentInfo nsIPresShell::gCaptureInfo;
// convert a color value to a string, in the CSS format #RRGGBB
// * - initially created for bugs 31816, 20760, 22963
@ -798,7 +797,6 @@ public:
NS_IMETHOD_(void) InvalidateFrameForView(nsIView *view);
NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
PRBool aFlushOnHoverChange);
NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView);
// caret handling
NS_IMETHOD GetCaret(nsCaret **aOutCaret);
@ -4372,41 +4370,6 @@ PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
}
}
NS_IMETHODIMP_(void)
PresShell::ClearMouseCapture(nsIView* aView)
{
if (gCaptureInfo.mContent) {
if (aView) {
// if a view was specified, ensure that the captured content
// is within this view
nsIFrame* frame = GetPrimaryFrameFor(gCaptureInfo.mContent);
if (frame) {
nsIView* view = frame->GetClosestView();
while (view) {
if (view == aView) {
NS_RELEASE(gCaptureInfo.mContent);
// the view containing the captured content likely disappeared so
// disable capture for now.
gCaptureInfo.mAllowed = PR_FALSE;
break;
}
view = view->GetParent();
}
// return if the view wasn't found
return;
}
}
NS_RELEASE(gCaptureInfo.mContent);
}
// disable mouse capture until the next mousedown as a dialog has opened
// or a drag has started. Otherwise, someone could start capture during
// the modal dialog or drag.
gCaptureInfo.mAllowed = PR_FALSE;
}
NS_IMETHODIMP
PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
{
@ -5730,22 +5693,6 @@ PresShell::PaintDefaultBackground(nsIView* aView,
return NS_OK;
}
// static
void
nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
{
NS_IF_RELEASE(gCaptureInfo.mContent);
// only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
// is used
if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed) {
if (aContent) {
NS_ADDREF(gCaptureInfo.mContent = aContent);
}
gCaptureInfo.mRetargetToElement = (aFlags & CAPTURE_RETARGETTOELEMENT) != 0;
}
}
nsIFrame*
PresShell::GetCurrentEventFrame()
{
@ -5902,49 +5849,40 @@ PresShell::HandleEvent(nsIView *aView,
}
#endif
nsCOMPtr<nsIDocument> retargetEventDoc;
// key and IME events must be targeted at the presshell for the focused frame
if (!sDontRetargetEvents) {
if (NS_IsEventTargetedAtFocusedWindow(aEvent)) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (!fm)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> window;
fm->GetFocusedWindow(getter_AddRefs(window));
if (!sDontRetargetEvents && NS_IsEventTargetedAtFocusedWindow(aEvent)) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (!fm)
return NS_ERROR_FAILURE;
// if there is no focused frame, there isn't anything to fire a key event
// at so just return
nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(window);
if (!piWindow)
return NS_OK;
nsCOMPtr<nsIDOMWindow> window;
fm->GetFocusedWindow(getter_AddRefs(window));
retargetEventDoc = do_QueryInterface(piWindow->GetExtantDocument());
if (!retargetEventDoc)
return NS_OK;
} else if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
// if the mouse is being captured then retarget the mouse event at the
// document that is being captured.
retargetEventDoc = gCaptureInfo.mContent->GetCurrentDoc();
}
// if there is no focused frame, there isn't anything to fire a key event
// at so just return
nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(window);
if (!piWindow)
return NS_OK;
if (retargetEventDoc) {
nsIPresShell* presShell = retargetEventDoc->GetPrimaryShell();
if (!presShell)
return NS_OK;
nsCOMPtr<nsIDocument> doc(do_QueryInterface(piWindow->GetExtantDocument()));
if (!doc)
return NS_OK;
if (presShell != this) {
nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(presShell);
if (!viewObserver)
return NS_ERROR_FAILURE;
nsIPresShell *presShell = doc->GetPrimaryShell();
if (!presShell)
return NS_OK;
nsIView *view;
presShell->GetViewManager()->GetRootView(view);
sDontRetargetEvents = PR_TRUE;
nsresult rv = viewObserver->HandleEvent(view, aEvent, aEventStatus);
sDontRetargetEvents = PR_FALSE;
return rv;
}
if (presShell != this) {
nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(presShell);
if (!viewObserver)
return NS_ERROR_FAILURE;
nsIView *view;
presShell->GetViewManager()->GetRootView(view);
sDontRetargetEvents = PR_TRUE;
nsresult rv = viewObserver->HandleEvent(view, aEvent, aEventStatus);
sDontRetargetEvents = PR_FALSE;
return rv;
}
}
@ -5995,41 +5933,8 @@ PresShell::HandleEvent(nsIView *aView,
return NS_OK;
}
PRBool getDescendantPoint = PR_TRUE;
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
// if a node is capturing the mouse, get the frame for the capturing
// content and use that instead. However, if the content has no parent,
// such as the root frame, get the parent canvas frame instead. This
// ensures that positioned frames are included when hit-testing.
nsIContent* capturingContent = gCaptureInfo.mContent;
frame = GetPrimaryFrameFor(capturingContent);
if (frame) {
getDescendantPoint = !gCaptureInfo.mRetargetToElement;
if (!capturingContent->GetParent()) {
frame = frame->GetParent();
}
else {
// special case for <select> as it needs to capture on the dropdown list.
if (capturingContent->Tag() == nsGkAtoms::select &&
capturingContent->IsNodeOfType(nsINode::eHTML)) {
nsIFrame* childframe = frame->GetChildList(nsGkAtoms::selectPopupList).FirstChild();
if (childframe) {
frame = childframe;
}
}
// if the frame is a scrolling frame, get the inner scrolled frame instead.
nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
if (scrollFrame) {
frame = scrollFrame->GetScrolledFrame();
}
}
aView = frame->GetClosestView();
}
}
PRBool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
// if this event has no frame, we need to retarget it at a parent
@ -6082,19 +5987,17 @@ PresShell::HandleEvent(nsIView *aView,
#endif
}
nsIFrame* targetFrame = nsnull;
if (getDescendantPoint) {
nsPoint eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
{
nsAutoDisableGetUsedXAssertions disableAssert;
PRBool ignoreRootScrollFrame = PR_FALSE;
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
}
targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
PR_FALSE, ignoreRootScrollFrame);
nsPoint eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
nsIFrame* targetFrame;
{
nsAutoDisableGetUsedXAssertions disableAssert;
PRBool ignoreRootScrollFrame = PR_FALSE;
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
}
targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
PR_FALSE, ignoreRootScrollFrame);
}
if (targetFrame) {
@ -6374,8 +6277,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
}
}
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
aEvent->message == NS_MOUSE_BUTTON_DOWN);
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
@ -6421,11 +6323,6 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
weakView.GetView());
}
}
if (aEvent->message == NS_MOUSE_BUTTON_UP) {
// reset the capturing content now that the mouse button is up
SetCapturingContent(nsnull, 0);
}
}
return rv;
}

Просмотреть файл

@ -1031,23 +1031,28 @@ nsListControlFrame::CaptureMouseEvents(PRBool aGrabMouseEvents)
if (NS_UNLIKELY(!view))
return;
if (aGrabMouseEvents) {
nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
} else {
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
PRBool dropDownIsHidden = PR_FALSE;
if (IsInDropDownMode()) {
dropDownIsHidden = !mComboboxFrame->IsDroppedDown();
}
if (capturingContent == mContent || dropDownIsHidden) {
// only clear the capturing content if *we* are the ones doing the
// capturing (or if the dropdown is hidden, in which case NO-ONE should
// be capturing anything - it could be a scrollbar inside this listbox
// which is actually grabbing
// This shouldn't be necessary. We should simply ensure that events targeting
// scrollbars are never visible to DOM consumers.
nsIPresShell::SetCapturingContent(nsnull, 0);
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
PRBool result;
// It's not clear why we don't have the widget capture mouse events here.
if (aGrabMouseEvents) {
viewMan->GrabMouseEvents(view, result);
} else {
nsIView* curGrabber;
viewMan->GetMouseEventGrabber(curGrabber);
PRBool dropDownIsHidden = PR_FALSE;
if (IsInDropDownMode()) {
dropDownIsHidden = !mComboboxFrame->IsDroppedDown();
}
if (curGrabber == view || dropDownIsHidden) {
// only unset the grabber if *we* are the ones doing the grabbing
// (or if the dropdown is hidden, in which case NO-ONE should be
// grabbing anything
// it could be a scrollbar inside this listbox which is actually grabbing
// This shouldn't be necessary. We should simply ensure that events targeting
// scrollbars are never visible to DOM consumers.
viewMan->GrabMouseEvents(nsnull, result);
}
}
}
}
@ -2115,7 +2120,11 @@ nsListControlFrame::GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent,
if (IgnoreMouseEventForSelection(aMouseEvent))
return NS_ERROR_FAILURE;
if (nsIPresShell::GetCapturingContent() != mContent) {
nsIView* view = GetScrolledFrame()->GetView();
nsIViewManager* viewMan = view->GetViewManager();
nsIView* curGrabber;
viewMan->GetMouseEventGrabber(curGrabber);
if (curGrabber != view) {
// If we're not capturing, then ignore movement in the border
nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(aMouseEvent, this);
nsRect borderInnerEdge = GetScrollableView()->View()->GetBounds();

Просмотреть файл

@ -55,7 +55,6 @@
#include "nsStyleContext.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsIScrollableView.h"
#include "nsIScrollableFrame.h"
#include "nsPresContext.h"
#include "nsCRT.h"
@ -752,17 +751,18 @@ nsFrame::GetChildList(nsIAtom* aListName) const
}
static nsIFrame*
GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
GetActiveSelectionFrame(nsIFrame* aFrame)
{
nsIPresShell* shell = aPresContext->GetPresShell();
if (shell) {
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
if (capturingContent) {
nsIFrame* activeFrame = shell->GetPrimaryFrameFor(capturingContent);
return activeFrame ? activeFrame : aFrame;
nsIView* mouseGrabber;
aFrame->PresContext()->GetPresShell()->
GetViewManager()->GetMouseEventGrabber(mouseGrabber);
if (mouseGrabber) {
nsIFrame* activeFrame = nsLayoutUtils::GetFrameFor(mouseGrabber);
if (activeFrame) {
return activeFrame;
}
}
return aFrame;
}
@ -1915,23 +1915,8 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
// NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
PRBool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
// If the mouse is dragged outside the nearest enclosing scrollable area
// while making a selection, the area will be scrolled. To do this, capture
// the mouse on the nearest scrollable frame. If there isn't a scrollable
// frame, or something else is already capturing the mouse, there's no
// reason to capture.
if (!nsIPresShell::GetCapturingContent()) {
nsIFrame* checkFrame = this;
nsIScrollableFrame *scrollFrame = nsnull;
while (checkFrame) {
scrollFrame = do_QueryFrame(checkFrame);
if (scrollFrame) {
nsIPresShell::SetCapturingContent(checkFrame->GetContent(), CAPTURE_IGNOREALLOWED);
break;
}
checkFrame = checkFrame->GetParent();
}
}
if (!IsMouseCaptured(aPresContext))
CaptureMouse(aPresContext, PR_TRUE);
// XXX This is screwy; it really should use the selection frame, not the
// event frame
@ -2206,6 +2191,29 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
return frameSelection->MaintainSelection(aAmountBack);
}
// Figure out which view we should point capturing at, given that drag started
// in this frame.
static nsIView* GetNearestCapturingView(nsIFrame* aFrame) {
nsIView* view = nsnull;
while (!(view = aFrame->GetMouseCapturer()) && aFrame->GetParent()) {
aFrame = aFrame->GetParent();
}
if (!view) {
// Use the root view. The root frame always has the root view.
view = aFrame->GetView();
}
NS_ASSERTION(view, "No capturing view found");
return view;
}
nsIFrame* nsFrame::GetNearestCapturingFrame(nsIFrame* aFrame) {
nsIFrame* captureFrame = aFrame;
while (captureFrame && !captureFrame->GetMouseCapturer()) {
captureFrame = captureFrame->GetParent();
}
return captureFrame;
}
NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
@ -2230,6 +2238,13 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
frameselection->StopAutoScrollTimer();
// If we have capturing view, it must be ensured that |this| doesn't
// get deleted during HandleDrag.
nsWeakFrame weakFrame = GetNearestCapturingView(this) ? this : nsnull;
#ifdef NS_DEBUG
PRBool frameAlive = weakFrame.IsAlive();
#endif
// Check if we are dragging in a table cell
nsCOMPtr<nsIContent> parentContent;
PRInt32 contentOffset;
@ -2247,29 +2262,22 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
frameselection->HandleDrag(this, pt);
}
// get the nearest scrollframe
nsIFrame* checkFrame = this;
nsIScrollableFrame *scrollFrame = nsnull;
while (checkFrame) {
scrollFrame = do_QueryFrame(checkFrame);
if (scrollFrame) {
break;
}
checkFrame = checkFrame->GetParent();
}
if (scrollFrame) {
nsIView* capturingView = scrollFrame->GetScrollableView()->View();
if (capturingView) {
if (weakFrame) {
nsIView* captureView = GetNearestCapturingView(this);
if (captureView) {
// Get the view that aEvent->point is relative to. This is disgusting.
nsIView* eventView = nsnull;
nsPoint pt = nsLayoutUtils::GetEventCoordinatesForNearestView(aEvent, this,
&eventView);
nsPoint capturePt = pt + eventView->GetOffsetTo(capturingView);
frameselection->StartAutoScrollTimer(capturingView, capturePt, 30);
nsPoint capturePt = pt + eventView->GetOffsetTo(captureView);
frameselection->StartAutoScrollTimer(captureView, capturePt, 30);
}
}
#ifdef NS_DEBUG
if (frameAlive && !weakFrame.IsAlive()) {
NS_WARNING("nsFrame deleted during nsFrame::HandleDrag.");
}
#endif
return NS_OK;
}
@ -2342,11 +2350,11 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
nsIFrame* activeFrame = GetActiveSelectionFrame(this);
// We can unconditionally stop capturing because
// we should never be capturing when the mouse button is up
nsIPresShell::SetCapturingContent(nsnull, 0);
CaptureMouse(aPresContext, PR_FALSE);
PRBool selectionOff =
(DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
@ -5931,6 +5939,51 @@ nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
}
}
NS_IMETHODIMP
nsFrame::CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
{
// get its view
nsIView* view = GetNearestCapturingView(this);
if (!view) {
return NS_ERROR_FAILURE;
}
nsIViewManager* viewMan = view->GetViewManager();
if (!viewMan) {
return NS_ERROR_FAILURE;
}
if (aGrabMouseEvents) {
PRBool result;
viewMan->GrabMouseEvents(view, result);
} else {
PRBool result;
viewMan->GrabMouseEvents(nsnull, result);
}
return NS_OK;
}
PRBool
nsFrame::IsMouseCaptured(nsPresContext* aPresContext)
{
// get its view
nsIView* view = GetNearestCapturingView(this);
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
nsIView* grabbingView;
viewMan->GetMouseEventGrabber(grabbingView);
if (grabbingView == view)
return PR_TRUE;
}
}
return PR_FALSE;
}
nsresult
nsIFrame::SetProperty(nsIAtom* aPropName,
void* aPropValue,

Просмотреть файл

@ -202,6 +202,14 @@ public:
PRInt8 aOutSideLimit
);
/**
* Find the nearest frame with a mouse capturer. If no
* parent has mouse capture this will return null.
* @param aFrame Frame drag began in.
* @return Nearest capturing frame.
*/
static nsIFrame* GetNearestCapturingFrame(nsIFrame* aFrame);
NS_IMETHOD CharacterDataChanged(CharacterDataChangeInfo* aInfo);
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -394,6 +402,10 @@ public:
void ConsiderChildOverflow(nsRect& aOverflowArea,
nsIFrame* aChildFrame);
//Mouse Capturing code used by the frames to tell the view to capture all the following events
NS_IMETHOD CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents);
PRBool IsMouseCaptured(nsPresContext* aPresContext);
virtual const void* GetStyleDataExternal(nsStyleStructID aSID) const;

Просмотреть файл

@ -314,6 +314,19 @@ nsHTMLFramesetFrame::Init(nsIContent* aContent,
nsPresContext* presContext = PresContext();
nsIPresShell* shell = presContext->PresShell();
// create the view. a view is needed since it needs to be a mouse grabber
nsIViewManager* viewMan = shell->GetViewManager();
nsIView *parView = GetAncestorWithView()->GetView();
nsRect boundBox(0, 0, 0, 0);
nsIView* view = viewMan->CreateView(boundBox, parView);
if (!view)
return NS_ERROR_OUT_OF_MEMORY;
// XXX Put it last in document order until we can do better
viewMan->InsertChild(parView, view, nsnull, PR_TRUE);
SetView(view);
nsFrameborder frameborder = GetFrameBorder();
PRInt32 borderWidth = GetBorderWidth(presContext, PR_FALSE);
nscolor borderColor = GetBorderColor();
@ -798,6 +811,28 @@ NS_METHOD nsHTMLFramesetFrame::HandleEvent(nsPresContext* aPresContext,
return NS_OK;
}
#if 0
PRBool
nsHTMLFramesetFrame::IsGrabbingMouse()
{
PRBool result = PR_FALSE;
nsIView* view = GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
nsIView* grabber;
viewMan->GetMouseEventGrabber(grabber);
if (grabber == view) {
// the nsFramesetBorderFrame has captured NS_MOUSE_DOWN
result = PR_TRUE;
}
NS_RELEASE(viewMan);
}
}
return result;
}
#endif
NS_IMETHODIMP
nsHTMLFramesetFrame::GetCursor(const nsPoint& aPoint,
nsIFrame::Cursor& aCursor)
@ -1442,23 +1477,28 @@ nsHTMLFramesetFrame::StartMouseDrag(nsPresContext* aPresContext,
IndexOf(aBorder, index);
NS_ASSERTION((nsnull != aBorder) && (index >= 0), "invalid dragger");
#endif
nsIView* view = GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
PRBool ignore;
viewMan->GrabMouseEvents(view, ignore);
mDragger = aBorder;
nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
mFirstDragPoint = aEvent->refPoint;
mDragger = aBorder;
// Store the original frame sizes
if (mDragger->mVertical) {
mPrevNeighborOrigSize = mColSizes[mDragger->mPrevNeighbor];
mNextNeighborOrigSize = mColSizes[mDragger->mNextNeighbor];
} else {
mPrevNeighborOrigSize = mRowSizes[mDragger->mPrevNeighbor];
mNextNeighborOrigSize = mRowSizes[mDragger->mNextNeighbor];
}
mFirstDragPoint = aEvent->refPoint;
// Store the original frame sizes
if (mDragger->mVertical) {
mPrevNeighborOrigSize = mColSizes[mDragger->mPrevNeighbor];
mNextNeighborOrigSize = mColSizes[mDragger->mNextNeighbor];
} else {
mPrevNeighborOrigSize = mRowSizes[mDragger->mPrevNeighbor];
mNextNeighborOrigSize = mRowSizes[mDragger->mNextNeighbor];
gDragInProgress = PR_TRUE;
}
}
gDragInProgress = PR_TRUE;
}
@ -1539,10 +1579,17 @@ nsHTMLFramesetFrame::MouseDrag(nsPresContext* aPresContext,
void
nsHTMLFramesetFrame::EndMouseDrag(nsPresContext* aPresContext)
{
nsIPresShell::SetCapturingContent(nsnull, 0);
mDragger = nsnull;
nsIView* view = GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
mDragger = nsnull;
PRBool ignore;
viewMan->GrabMouseEvents(nsnull, ignore);
}
}
gDragInProgress = PR_FALSE;
}
}
nsIFrame*
NS_NewHTMLFramesetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)

Просмотреть файл

@ -309,6 +309,10 @@ public:
return mInner.GetScrolledFrame()->GetContentInsertionFrame();
}
virtual nsIView* GetMouseCapturer() const {
return mInner.GetScrolledFrame()->GetView();
}
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags);
@ -472,6 +476,10 @@ public:
return mInner.GetScrolledFrame()->GetContentInsertionFrame();
}
virtual nsIView* GetMouseCapturer() const {
return mInner.GetScrolledFrame()->GetView();
}
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags);

Просмотреть файл

@ -107,10 +107,9 @@ struct CharacterDataChangeInfo;
typedef class nsIFrame nsIBox;
// 87F5B42A-507D-4707-976C-46819867BC63
#define NS_IFRAME_IID \
{ 0x87f5b42a, 0x507d, 0x4707, \
{ 0x97, 0x6c, 0x46, 0x81, 0x98, 0x67, 0xbc, 0x63 } }
{ 0x7e9018b5, 0x5405, 0x4e2b, \
{ 0x87, 0x67, 0xe2, 0xb4, 0xb1, 0x3e, 0xc1, 0x69 } }
/**
* Indication of how the frame can be split. This is used when doing runaround
@ -1733,6 +1732,14 @@ public:
*/
virtual PRBool IsLeaf() const;
/**
* Does this frame want to capture the mouse when the user clicks in
* it or its children? If so, return the view which should be
* targeted for mouse capture. The view need not be this frame's view,
* it could be the view on a child.
*/
virtual nsIView* GetMouseCapturer() const { return nsnull; }
/**
* @param aFlags see InvalidateInternal below
*/
@ -1947,6 +1954,14 @@ public:
/** EndSelection related calls
*/
/**
* Call to turn on/off mouseCapture at the view level. Needed by the ESM so
* it must be in the public interface.
* @param aPresContext presContext associated with the frame
* @param aGrabMouseEvents PR_TRUE to enable capture, PR_FALSE to disable
*/
NS_IMETHOD CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents) = 0;
/**
* called to find the previous/next character, word, or line returns the actual
* nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE

Просмотреть файл

@ -414,7 +414,7 @@ public:
mTimer->Cancel();
}
nsresult Start(nsPresContext *aPresContext, nsPoint &aPoint)
nsresult Start(nsPresContext *aPresContext, nsIView *aView, nsPoint &aPoint)
{
mPoint = aPoint;
@ -422,7 +422,36 @@ public:
// stopped by the selection if the prescontext is destroyed.
mPresContext = aPresContext;
mContent = nsIPresShell::GetCapturingContent();
// Store the content from the nearest capturing frame. If this returns null
// the capturing frame is the root.
nsIFrame* clientFrame = static_cast<nsIFrame*>(aView->GetClientData());
NS_ASSERTION(clientFrame, "Missing client frame");
nsIFrame* capturingFrame = nsFrame::GetNearestCapturingFrame(clientFrame);
NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
"Capturing frame should have a mouse capturer" );
NS_ASSERTION(!capturingFrame || mPresContext == capturingFrame->PresContext(),
"Shouldn't have different pres contexts");
NS_ASSERTION(capturingFrame != mPresContext->PresShell()->FrameManager()->GetRootFrame(),
"Capturing frame should not be the root frame");
if (capturingFrame)
{
mContent = capturingFrame->GetContent();
NS_ASSERTION(mContent, "Need content");
NS_ASSERTION(mContent != mPresContext->PresShell()->FrameManager()->GetRootFrame()->GetContent(),
"We didn't want the root content!");
NS_ASSERTION(capturingFrame == nsFrame::GetNearestCapturingFrame(
mPresContext->PresShell()->GetPrimaryFrameFor(mContent)),
"Mapping of frame to content failed.");
}
// Check that if there was no capturing frame the content is null.
NS_ASSERTION(capturingFrame || !mContent, "Content not cleared correctly.");
if (!mTimer)
{
@ -465,14 +494,46 @@ public:
{
if (mSelection && mPresContext)
{
nsWeakFrame frame = mPresContext->PresShell()->GetPrimaryFrameFor(mContent);
// If the content is null the capturing frame must be the root frame.
nsIFrame* capturingFrame;
if (mContent)
{
nsIFrame* contentFrame = mPresContext->PresShell()->GetPrimaryFrameFor(mContent);
if (contentFrame)
{
capturingFrame = nsFrame::GetNearestCapturingFrame(contentFrame);
}
else
{
capturingFrame = nsnull;
}
NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
"Capturing frame should have a mouse capturer" );
}
else
{
capturingFrame = mPresContext->PresShell()->FrameManager()->GetRootFrame();
}
// Clear the content reference now that the frame has been found.
mContent = nsnull;
mFrameSelection->HandleDrag(frame, mPoint);
// This could happen for a frame with style changed to display:none or a frame
// that was destroyed.
if (!capturingFrame) {
NS_WARNING("Frame destroyed or set to display:none before scroll timer fired.");
return NS_OK;
}
nsIView* captureView = capturingFrame->GetMouseCapturer();
nsWeakFrame viewFrame = static_cast<nsIFrame*>(captureView->GetClientData());
NS_ASSERTION(viewFrame.GetFrame(), "View must have a client frame");
mFrameSelection->HandleDrag(viewFrame, mPoint);
nsPoint pnt;
mSelection->DoAutoScrollView(mPresContext,
frame.IsAlive() ? frame->GetClosestView(&pnt) : nsnull,
viewFrame.IsAlive() ? captureView : nsnull,
mPoint, PR_TRUE);
}
return NS_OK;
@ -4944,7 +5005,7 @@ nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext,
NS_ENSURE_SUCCESS(result, result);
nsPoint svPoint = globalPoint - globalOffset;
mAutoScrollTimer->Start(aPresContext, svPoint);
mAutoScrollTimer->Start(aPresContext, aView, svPoint);
}
return NS_OK;

Просмотреть файл

@ -109,7 +109,8 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
mTrackingMouseMove = PR_TRUE;
// start capture.
nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
aEvent->widget->CaptureMouse(PR_TRUE);
CaptureMouseEvents(aPresContext,PR_TRUE);
// remember current mouse coordinates.
mLastPoint = aEvent->refPoint;
@ -133,7 +134,8 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
mTrackingMouseMove = PR_FALSE;
// end capture
nsIPresShell::SetCapturingContent(nsnull, 0);
aEvent->widget->CaptureMouse(PR_FALSE);
CaptureMouseEvents(aPresContext,PR_FALSE);
*aEventStatus = nsEventStatus_eConsumeNoDefault;
doDefault = PR_FALSE;

Просмотреть файл

@ -55,6 +55,7 @@
#include "nsIPresShell.h"
#include "nsCSSRendering.h"
#include "nsIDOMEventTarget.h"
#include "nsIViewManager.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDocument.h"
#include "nsScrollbarButtonFrame.h"
@ -121,6 +122,7 @@ nsSliderFrame::Init(nsIContent* aContent,
mCurPos = GetCurrentPosition(aContent);
CreateViewForFrame(PresContext(), this, GetStyleContext(), PR_TRUE);
return rv;
}
@ -975,14 +977,42 @@ nsSliderFrame::DragThumb(PRBool aGrabMouseEvents)
}
}
nsIPresShell::SetCapturingContent(aGrabMouseEvents ? GetContent() : nsnull,
aGrabMouseEvents ? CAPTURE_IGNOREALLOWED : 0);
// get its view
nsIView* view = GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
PRBool result;
if (aGrabMouseEvents) {
viewMan->GrabMouseEvents(view,result);
} else {
viewMan->GrabMouseEvents(nsnull,result);
}
}
}
}
PRBool
nsSliderFrame::isDraggingThumb()
{
return (nsIPresShell::GetCapturingContent() == GetContent());
// get its view
nsIView* view = GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
nsIView* grabbingView;
viewMan->GetMouseEventGrabber(grabbingView);
if (grabbingView == view)
return PR_TRUE;
}
}
return PR_FALSE;
}
void

Просмотреть файл

@ -184,6 +184,8 @@ public:
static PRInt32 GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 defaultValue);
void EnsureOrient();
virtual nsIView* GetMouseCapturer() const { return GetView(); }
NS_IMETHOD HandlePress(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);

Просмотреть файл

@ -55,6 +55,9 @@
#include "nsIDOMMouseListener.h"
#include "nsIDOMMouseMotionListener.h"
#include "nsIDOMEventTarget.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsIScrollableView.h"
#include "nsIDOMMouseEvent.h"
#include "nsIPresShell.h"
#include "nsFrameList.h"
@ -144,6 +147,8 @@ public:
ResizeType GetResizeAfter();
State GetState();
//nsresult CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents);
//PRBool IsMouseCaptured(nsPresContext* aPresContext);
void Reverse(nsSplitterInfo*& aIndexes, PRInt32 aCount);
PRBool SupportsCollapseDirection(CollapseDirection aDirection);
@ -162,6 +167,7 @@ public:
PRInt32 mChildInfosAfterCount;
State mState;
nscoord mSplitterPos;
nscoord mSplitterViewPos;
PRBool mDragging;
};
@ -345,6 +351,9 @@ nsSplitterFrame::Init(nsIContent* aContent,
nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
mInner->mState = nsSplitterFrameInner::Open;
mInner->AddListener(PresContext());
mInner->mParentBox = nsnull;
@ -463,7 +472,7 @@ nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext, nsGUIEvent* aEvent)
if (mDragging && mOuter) {
AdjustChildren(aPresContext);
AddListener(aPresContext);
nsIPresShell::SetCapturingContent(nsnull, 0); // XXXndeakin is this needed?
mOuter->CaptureMouse(aPresContext, PR_FALSE);
mDragging = PR_FALSE;
State newState = GetState();
// if the state is dragging then make it Open.
@ -577,6 +586,20 @@ nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent)
AdjustChildren(aPresContext);
}
// printf("----- resize ----- ");
/*
for (i=0; i < mChildInfosBeforeCount; i++)
printf("before, index=%d, current=%d, changed=%d\n", mChildInfosBefore[i].index, mChildInfosBefore[i].current, mChildInfosBefore[i].changed);
for (i=0; i < mChildInfosAfterCount; i++)
printf("after, index=%d, current=%d, changed=%d\n", mChildInfosAfter[i].index, mChildInfosAfter[i].current, mChildInfosAfter[i].changed);
*/
/*
nsIPresShell *shell = aPresContext->PresShell();
shell->FrameNeedsReflow(mOuter, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
*/
mDidDrag = PR_TRUE;
}
}
@ -604,13 +627,62 @@ nsSplitterFrameInner::RemoveListener()
NS_GET_IID(nsIDOMMouseMotionListener));
}
/*
nsresult
nsSplitterFrameInner :: CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
{
// get its view
nsIView* view = mOuter->GetView();
PRBool result;
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
// nsIWidget* widget = view->GetWidget();
if (aGrabMouseEvents) {
viewMan->GrabMouseEvents(view,result);
// if (widget)
// widget->CaptureMouse(PR_TRUE);
} else {
viewMan->GrabMouseEvents(nsnull,result);
// if (widget)
// widget->CaptureMouse(PR_FALSE);
}
}
}
return NS_OK;
}
PRBool
nsSplitterFrameInner :: IsMouseCaptured(nsPresContext* aPresContext)
{
// get its view
nsIView* view = mOuter->GetView();
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
nsIView* grabbingView;
viewMan->GetMouseEventGrabber(grabbingView);
if (grabbingView == view)
return PR_TRUE;
}
}
return PR_FALSE;
}
*/
nsresult
nsSplitterFrameInner::MouseUp(nsIDOMEvent* aMouseEvent)
{
NS_ENSURE_TRUE(mOuter, NS_OK);
mPressed = PR_FALSE;
nsIPresShell::SetCapturingContent(nsnull, 0);
mOuter->CaptureMouse(mOuter->PresContext(), PR_FALSE);
return NS_OK;
}
@ -771,22 +843,26 @@ nsSplitterFrameInner::MouseDown(nsIDOMEvent* aMouseEvent)
if (resizeAfter == Grow)
mChildInfosAfterCount = 0;
nsRect vr = mOuter->GetView()->GetBounds();
PRInt32 c;
nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent,
mParentBox);
if (isHorizontal) {
c = pt.x;
mSplitterPos = mOuter->mRect.x;
mSplitterViewPos = vr.x;
} else {
c = pt.y;
mSplitterPos = mOuter->mRect.y;
mSplitterViewPos = vr.y;
}
mDragStart = c;
//printf("Pressed mDragStart=%d\n",mDragStart);
nsIPresShell::SetCapturingContent(mOuter->GetContent(), CAPTURE_IGNOREALLOWED);
mOuter->CaptureMouse(outerPresContext, PR_TRUE);
return NS_OK;
}

Просмотреть файл

@ -102,6 +102,8 @@ public:
virtual void GetInitialOrientation(PRBool& aIsHorizontal);
virtual nsIView* GetMouseCapturer() const { return GetView(); }
private:
friend class nsSplitterFrameInner;

Просмотреть файл

@ -48,6 +48,7 @@
#include "nsPresContext.h"
#include "nsIDocShellTreeItem.h"
#include "nsPIDOMWindow.h"
#include "nsIViewManager.h"
#include "nsGUIEvent.h"
#include "nsEventDispatcher.h"
#include "nsDisplayList.h"
@ -70,6 +71,20 @@ nsTitleBarFrame::nsTitleBarFrame(nsIPresShell* aPresShell, nsStyleContext* aCont
mTrackingMouseMove = PR_FALSE;
}
NS_IMETHODIMP
nsTitleBarFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* asPrevInFlow)
{
nsresult rv = nsBoxFrame::Init(aContent, aParent, asPrevInFlow);
CreateViewForFrame(PresContext(), this, GetStyleContext(), PR_TRUE);
return rv;
}
NS_IMETHODIMP
nsTitleBarFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
@ -114,7 +129,7 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
mTrackingMouseMove = PR_TRUE;
// start capture.
nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
CaptureMouseEvents(aPresContext,PR_TRUE);
// remember current mouse coordinates.
mLastPoint = aEvent->refPoint;
@ -137,7 +152,7 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
mTrackingMouseMove = PR_FALSE;
// end capture
nsIPresShell::SetCapturingContent(nsnull, 0);
CaptureMouseEvents(aPresContext,PR_FALSE);
*aEventStatus = nsEventStatus_eConsumeNoDefault;
doDefault = PR_FALSE;
@ -195,6 +210,35 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsTitleBarFrame::CaptureMouseEvents(nsPresContext* aPresContext,PRBool aGrabMouseEvents)
{
// get its view
nsIView* view = GetView();
PRBool result;
if (view) {
nsIViewManager* viewMan = view->GetViewManager();
if (viewMan) {
// nsIWidget* widget = view->GetWidget();
if (aGrabMouseEvents) {
viewMan->GrabMouseEvents(view,result);
//mIsCapturingMouseEvents = PR_TRUE;
//widget->CaptureMouse(PR_TRUE);
} else {
viewMan->GrabMouseEvents(nsnull,result);
//mIsCapturingMouseEvents = PR_FALSE;
//widget->CaptureMouse(PR_FALSE);
}
}
}
return NS_OK;
}
void
nsTitleBarFrame::MouseClicked(nsPresContext* aPresContext, nsGUIEvent* aEvent)
{

Просмотреть файл

@ -48,6 +48,10 @@ public:
nsTitleBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* asPrevInFlow);
NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
@ -60,6 +64,10 @@ public:
virtual void MouseClicked(nsPresContext* aPresContext, nsGUIEvent* aEvent);
protected:
NS_IMETHOD CaptureMouseEvents(nsPresContext* aPresContext,PRBool aGrabMouseEvents);
protected:
PRBool mTrackingMouseMove;
nsIntPoint mLastPoint;

Просмотреть файл

@ -2101,7 +2101,7 @@ nsXULMenuCommandEvent::Run()
if (mCloseMenuMode != CloseMenuMode_None)
menuFrame->SelectMenu(PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput, PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput);
nsContentUtils::DispatchXULCommand(mMenu, mIsTrusted, nsnull, shell,
mControl, mAlt, mShift, mMeta);
}

Просмотреть файл

@ -103,7 +103,6 @@ _TEST_FILES = test_bug360220.xul \
test_position.xul \
test_menu.xul \
test_menu_hide.xul \
test_mousecapture.xul \
test_focus.xul \
test_focus_anons.xul \
test_tabindex.xul \

Просмотреть файл

@ -1,191 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<window title="Mouse Capture Tests" align="start"
onload="setTimeout(runTests, 0);"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script>
<![CDATA[
SimpleTest.waitForExplicitFinish();
var captureRetargetMode = false;
var cachedMouseDown = null;
var previousWidth = 0, originalWidth = 0;
function splitterCallback(adjustment)
{
var newWidth = Number($("leftbox").width); // getBoundingClientRect().width;
var expectedWidth = previousWidth + adjustment;
if (expectedWidth > $("splitterbox").getBoundingClientRect().width)
expectedWidth = $("splitterbox").getBoundingClientRect().width - $("splitter").getBoundingClientRect().width;
is(newWidth, expectedWidth, "splitter left box size (" + adjustment + ")");
previousWidth = newWidth;
}
function selectionCallback(adjustment)
{
if (adjustment == 4000) {
is(frames[0].getSelection().toString(), "This is some text", "selection after drag (" + adjustment + ")");
ok(frames[0].scrollY > 40, "selection caused scroll down (" + adjustment + ")");
}
else {
if (adjustment == 0) {
is(frames[0].getSelection().toString(), ".", "selection after drag (" + adjustment + ")");
}
is(frames[0].scrollY, 0, "selection scrollY (" + adjustment + ")");
}
}
function framesetCallback(adjustment)
{
var newWidth = frames[1].frames[0].document.documentElement.clientWidth;
var expectedWidth = originalWidth + adjustment;
if (adjustment == 0)
expectedWidth = originalWidth - 12;
else if (expectedWidth >= 4000)
expectedWidth = originalWidth * 2 - 2;
is(newWidth, expectedWidth, "frameset after drag (" + adjustment + ")");
}
function runTests()
{
previousWidth = $("leftbox").getBoundingClientRect().width;
runCaptureTest($("splitter"), splitterCallback);
var custom = document.getElementById("custom");
runCaptureTest(custom);
synthesizeMouseExpectEvent($("rightbox"), 2, 2, { type: "mousemove" },
$("rightbox"), "mousemove", "setCapture and releaseCapture");
custom.setCapture();
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
$("leftbox"), "mousemove", "setCapture fails on non mousedown");
var custom2 = document.getElementById("custom2");
synthesizeMouse(custom2, 2, 2, { type: "mousedown" });
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
$("leftbox"), "mousemove", "document.releaseCapture releases capture");
var custom3 = document.getElementById("custom3");
synthesizeMouse(custom3, 2, 2, { type: "mousedown" });
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
$("leftbox"), "mousemove", "element.releaseCapture releases capture");
var custom4 = document.getElementById("custom4");
synthesizeMouse(custom4, 2, 2, { type: "mousedown" });
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
custom4, "mousemove", "element.releaseCapture during mousemove before releaseCapture");
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
$("leftbox"), "mousemove", "element.releaseCapture during mousemove after releaseCapture");
var custom5 = document.getElementById("custom5");
runCaptureTest(custom5);
captureRetargetMode = true;
runCaptureTest(custom5);
captureRetargetMode = false;
var b = frames[0].document.getElementById("b");
runCaptureTest(b, selectionCallback);
previousWidth = frames[1].frames[0].document.documentElement.clientWidth;
originalWidth = previousWidth;
runCaptureTest(frames[1].document.documentElement.lastChild, framesetCallback);
SimpleTest.finish();
}
function runCaptureTest(element, callback)
{
var expectedTarget = null;
var win = element.ownerDocument.defaultView;
function mouseMoved(event) {
is(event.originalTarget, expectedTarget,
expectedTarget.id + " target for point " + event.clientX + "," + event.clientY);
}
win.addEventListener("mousemove", mouseMoved, false);
expectedTarget = element;
var basepoint = element.localName == "frameset" ? 50 : 2;
synthesizeMouse(element, basepoint, basepoint, { type: "mousedown" }, win);
// in setCapture(true) mode, all events should fire on custom5. In
// setCapture(false) mode, events can fire at a descendant
if (expectedTarget == $("custom5") && !captureRetargetMode)
expectedTarget = $("custom5spacer");
// releaseCapture should do nothing for an element which isn't capturing
$("splitterbox").releaseCapture();
synthesizeMouse(element, basepoint + 2, basepoint + 2, { type: "mousemove" }, win);
if (callback)
callback(2);
if (expectedTarget == $("custom5spacer") && !captureRetargetMode)
expectedTarget = $("custom5inner");
synthesizeMouse(element, basepoint + 25, basepoint + 25, { type: "mousemove" }, win);
if (callback)
callback(25);
expectedTarget = element.localName == "b" ? win.document.documentElement : element;
synthesizeMouse(element, basepoint + 4000, basepoint + 4000, { type: "mousemove" }, win);
if (callback)
callback(4000);
synthesizeMouse(element, basepoint - 12, basepoint - 12, { type: "mousemove" }, win);
if (callback)
callback(-12);
expectedTarget = element.localName == "frameset" ? element : win.document.documentElement;
synthesizeMouse(element, basepoint + 30, basepoint + 30, { type: "mouseup" }, win);
synthesizeMouse(win.document.documentElement, 2, 2, { type: "mousemove" }, win);
if (callback)
callback(0);
win.removeEventListener("mousemove", mouseMoved, false);
}
]]>
</script>
<hbox id="splitterbox" style="margin-top: 5px;" onmousedown="this.setCapture()">
<hbox id="leftbox" width="100" flex="1"/>
<splitter id="splitter" height="5"/>
<hbox id="rightbox" width="100" flex="1"/>
</hbox>
<vbox id="custom" width="10" height="10" onmousedown="this.setCapture(); cachedMouseDown = event;"/>
<vbox id="custom2" width="10" height="10" onmousedown="this.setCapture(); document.releaseCapture();"/>
<vbox id="custom3" width="10" height="10" onmousedown="this.setCapture(); this.releaseCapture();"/>
<vbox id="custom4" width="10" height="10" onmousedown="this.setCapture();"
onmousemove="this.releaseCapture();"/>
<hbox id="custom5" width="40" height="40"
onmousedown="this.setCapture(captureRetargetMode);">
<spacer id="custom5spacer" width="5"/>
<hbox id="custom5inner" width="35" height="35"/>
</hbox>
<hbox>
<iframe width="100" height="100"
src="data:text/html,%3Cbody style%3D'font-size%3A 40pt%3B'%3E.%3Cb id%3D'b'%3EThis%3C/b%3E is some text%3C/body%3E"/>
<iframe width="100" height="100"
src="data:text/html,%3Cframeset cols='50%, 50%'%3E%3Cframe src='about:blank'%3E%3Cframe src='about:blank'%3E%3C/frameset%3E"/>
</hbox>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"/><div id="content" style="display: none"/><pre id="test"/>
</body>
</window>

Просмотреть файл

@ -212,17 +212,6 @@ function testtag_scale_UI_Mouse(element, testid, horiz, reverse, pinc)
is(element.value, endval, testid + " mouse on right movetoclick=false");
element.removeAttribute("movetoclick");
element.value = reverse ? element.max : element.min;
synthesizeMouse(element, 7, 7, { type: "mousedown" });
synthesizeMouse(element, 2000, 2000, { type: "mousemove" });
is(element.value, reverse ? element.min : element.max, testid + " move mouse too far before start");
synthesizeMouse(element, 2000, 2000, { type: "mouseup" });
synthesizeMouse(element, rect.width - 7, rect.height - 7, { type: "mousedown" });
synthesizeMouse(element, -2000, -2000, { type: "mousemove" });
is(element.value, reverse ? element.max : element.min, testid + " move mouse too far before end");
synthesizeMouse(element, -2000, -2000, { type: "mouseup" });
}
function testtag_scale_States(element, evalue, evalueattr, emin, emax, testid)

Просмотреть файл

@ -60,8 +60,8 @@ enum nsRectVisibility {
};
#define NS_IVIEWMANAGER_IID \
{ 0xe1f3095c, 0x65cd, 0x46e1, \
{ 0x9d, 0x70, 0x88, 0xcf, 0x54, 0x19, 0x9d, 0x05 } }
{ 0x739bbc2b, 0x5c45, 0x40bb, \
{ 0xb0, 0xbc, 0xe3, 0x1c, 0xe0, 0xf2, 0x19, 0xc2 } }
class nsIViewManager : public nsISupports
{
@ -187,6 +187,21 @@ public:
NS_IMETHOD DispatchEvent(nsGUIEvent *aEvent,
nsIView* aViewTarget, nsEventStatus* aStatus) = 0;
/**
* Used to grab/capture all mouse events for a specific view,
* irrespective of the cursor position at which the
* event occurred.
* @param aView view to capture mouse events
* @result event handling status
*/
NS_IMETHOD GrabMouseEvents(nsIView *aView, PRBool& aResult) = 0;
/**
* Get the current view, if any, that's capturing mouse events.
* @result view that is capturing mouse events or nsnull
*/
NS_IMETHOD GetMouseEventGrabber(nsIView *&aView) = 0;
/**
* Given a parent view, insert another view as its child.
* aSibling and aAbove control the "document order" for the insertion.

Просмотреть файл

@ -46,10 +46,10 @@
class nsIRenderingContext;
class nsGUIEvent;
// 8D7AE493-1EB1-4D38-89DA-9EEEAA29FD79
// 52b3b616-23a9-4516-a8d3-452b4126eb2b
#define NS_IVIEWOBSERVER_IID \
{ 0x8d7ae493, 0x1eb1, 0x4d38, \
{ 0x89, 0xda, 0x9e, 0xee, 0xaa, 0x29, 0xfd, 0x79 } }
{ 0x52b3b616, 0x23a9, 0x4516, \
{ 0xa8, 0xd3, 0x45, 0x2b, 0x41, 0x26, 0xeb, 0x2b } }
class nsIViewObserver : public nsISupports
{
@ -150,13 +150,6 @@ public:
*/
NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
PRBool aFlushOnHoverChange) = 0;
/**
* If something within aView is capturing the mouse, clear the capture.
* if aView is null, clear the mouse capture no matter what is capturing it.
*/
NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewObserver, NS_IVIEWOBSERVER_IID)

Просмотреть файл

@ -185,11 +185,13 @@ nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
mDeletionObserver = nsnull;
}
void nsView::DropMouseGrabbing()
{
nsCOMPtr<nsIViewObserver> viewObserver = mViewManager->GetViewObserver();
if (viewObserver) {
viewObserver->ClearMouseCapture(this);
void nsView::DropMouseGrabbing() {
// check to see if we are grabbing events
if (mViewManager->GetMouseEventGrabber() == this) {
// we are grabbing events. Move the grab to the parent if we can.
PRBool boolResult; //not used
// if GetParent() returns null, then we release the grab, which is the best we can do
mViewManager->GrabMouseEvents(GetParent(), boolResult);
}
}
@ -493,6 +495,15 @@ NS_IMETHODIMP nsView::SetFloating(PRBool aFloatingView)
void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
{
if (aViewManagerParent) {
// We're removed from the view hierarchy of aRemovalPoint, so make sure
// we're not still grabbing mouse events.
if (aViewManagerParent->GetMouseEventGrabber() == this) {
PRBool res;
aViewManagerParent->GrabMouseEvents(nsnull, res);
}
}
if (mViewManager->GetRootView() == this)
mViewManager->InvalidateHierarchy();

Просмотреть файл

@ -263,6 +263,8 @@ NS_IMETHODIMP nsViewManager::Init(nsIDeviceContext* aContext)
mRefreshEnabled = PR_TRUE;
mMouseGrabber = nsnull;
return NS_OK;
}
@ -1075,24 +1077,31 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
}
if (aEvent->message == NS_DEACTIVATE) {
// if a window is deactivated, clear the mouse capture regardless
// of what is capturing
nsIViewObserver* viewObserver = GetViewObserver();
if (viewObserver) {
viewObserver->ClearMouseCapture(nsnull);
}
PRBool result;
GrabMouseEvents(nsnull, result);
}
//Find the view whose coordinates system we're in.
nsView* baseView = static_cast<nsView*>(aView);
nsView* view = baseView;
PRBool capturedEvent = PR_FALSE;
if (NS_IsEventUsingCoordinates(aEvent)) {
// will dispatch using coordinates. Pretty bogus but it's consistent
// with what presshell does.
view = GetDisplayRootFor(baseView);
}
//Find the view to which we're initially going to send the event
//for hittesting.
if (NS_IS_MOUSE_EVENT(aEvent) || NS_IS_DRAG_EVENT(aEvent)) {
nsView* mouseGrabber = GetMouseEventGrabber();
if (mouseGrabber) {
view = mouseGrabber;
capturedEvent = PR_TRUE;
}
}
if (nsnull != view) {
PRInt32 p2a = mContext->AppUnitsPerDevPixel();
@ -1162,7 +1171,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
NSFloatPixelsToAppUnits(float(aEvent->refPoint.y) + 0.5f, p2a);
pt += offset;
*aStatus = HandleEvent(view, pt, aEvent);
*aStatus = HandleEvent(view, pt, aEvent, capturedEvent);
}
break;
@ -1173,7 +1182,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
}
nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsPoint aPoint,
nsGUIEvent* aEvent) {
nsGUIEvent* aEvent, PRBool aCaptured) {
//printf(" %d %d %d %d (%d,%d) \n", this, event->widget, event->widgetSupports,
// event->message, event->point.x, event->point.y);
@ -1189,6 +1198,37 @@ nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsPoint aPoint,
return status;
}
NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult)
{
if (!IsRootVM()) {
return RootViewManager()->GrabMouseEvents(aView, aResult);
}
// Along with nsView::SetVisibility, we enforce that the mouse grabber
// can never be a hidden view.
if (aView && !static_cast<nsView*>(aView)->IsEffectivelyVisible()) {
aView = nsnull;
}
#ifdef DEBUG_mjudge
if (aView)
{
printf("capturing mouse events for view %x\n",aView);
}
printf("removing mouse capture from view %x\n",mMouseGrabber);
#endif
mMouseGrabber = static_cast<nsView*>(aView);
aResult = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView)
{
aView = GetMouseEventGrabber();
return NS_OK;
}
// Recursively reparent widgets if necessary
void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)

Просмотреть файл

@ -128,6 +128,10 @@ public:
NS_IMETHOD DispatchEvent(nsGUIEvent *aEvent,
nsIView* aTargetView, nsEventStatus* aStatus);
NS_IMETHOD GrabMouseEvents(nsIView *aView, PRBool &aResult);
NS_IMETHOD GetMouseEventGrabber(nsIView *&aView);
NS_IMETHOD InsertChild(nsIView *parent, nsIView *child, nsIView *sibling,
PRBool above);
@ -301,10 +305,14 @@ private:
public: // NOT in nsIViewManager, so private to the view module
nsView* GetRootView() const { return mRootView; }
nsView* GetMouseEventGrabber() const {
return RootViewManager()->mMouseGrabber;
}
nsViewManager* RootViewManager() const { return mRootViewManager; }
PRBool IsRootVM() const { return this == RootViewManager(); }
nsEventStatus HandleEvent(nsView* aView, nsPoint aPoint, nsGUIEvent* aEvent);
nsEventStatus HandleEvent(nsView* aView, nsPoint aPoint, nsGUIEvent* aEvent,
PRBool aCaptured);
/**
* Called to inform the view manager that a view is about to bit-blit.
@ -382,6 +390,8 @@ private:
// the root view manager. Some have accessor functions to enforce
// this, as noted.
// Use GrabMouseEvents() and GetMouseEventGrabber() to access mMouseGrabber.
nsView *mMouseGrabber;
// Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
// ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
PRInt32 mUpdateCnt;

Просмотреть файл

@ -227,12 +227,20 @@ nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
// When the mouse goes down, the selection code starts a mouse
// capture. However, this gets in the way of determining drag
// feedback for things like trees because the event coordinates
// are in the wrong coord system, so turn off mouse capture.
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
if (doc) {
nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(doc->GetPrimaryShell());
if (viewObserver) {
viewObserver->ClearMouseCapture(nsnull);
// are in the wrong coord system. Turn off mouse capture in
// the associated view manager.
nsCOMPtr<nsIContent> contentNode = do_QueryInterface(aDOMNode);
if (contentNode) {
nsIDocument* doc = contentNode->GetCurrentDoc();
if (doc) {
nsIPresShell* presShell = doc->GetPrimaryShell();
if (presShell) {
nsIViewManager* vm = presShell->GetViewManager();
if (vm) {
PRBool notUsed;
vm->GrabMouseEvents(nsnull, notUsed);
}
}
}
}