nsresult HTMLLabelElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) { if (mHandlingEvent || (!NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) && aVisitor.mEvent->message != NS_MOUSE_BUTTON_DOWN) || aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || !aVisitor.mPresContext || // Don't handle the event if it's already been handled by another label aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return NS_OK; } // Strong ref because event dispatch is going to happen. nsRefPtr<Element> content = GetLabeledElement(); if (content && !EventTargetIn(aVisitor.mEvent, content, this)) { mHandlingEvent = true; switch (aVisitor.mEvent->message) { case NS_MOUSE_BUTTON_DOWN: NS_ASSERTION(aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT, "wrong event struct for event"); if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eLeftButton) { // We reset the mouse-down point on every event because there is // no guarantee we will reach the NS_MOUSE_CLICK code below. nsIntPoint *curPoint = new nsIntPoint(aVisitor.mEvent->refPoint); SetProperty(nsGkAtoms::labelMouseDownPtProperty, static_cast<void *>(curPoint), DestroyMouseDownPoint); } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) { const nsMouseEvent* event = static_cast<const nsMouseEvent*>(aVisitor.mEvent); nsIntPoint *mouseDownPoint = static_cast<nsIntPoint *> (GetProperty(nsGkAtoms::labelMouseDownPtProperty)); bool dragSelect = false; if (mouseDownPoint) { nsIntPoint dragDistance = *mouseDownPoint; DeleteProperty(nsGkAtoms::labelMouseDownPtProperty); dragDistance -= aVisitor.mEvent->refPoint; const int CLICK_DISTANCE = 2; dragSelect = dragDistance.x > CLICK_DISTANCE || dragDistance.x < -CLICK_DISTANCE || dragDistance.y > CLICK_DISTANCE || dragDistance.y < -CLICK_DISTANCE; } // Don't click the for-content if we did drag-select text or if we // have a kbd modifier (which adjusts a selection), or if it's a // double click (we already forwarded the first click event). if (dragSelect || event->clickCount > 1 || event->IsShift() || event->IsControl() || event->IsAlt() || event->IsMeta()) { break; } nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. // Also, within nsHTMLInputElement::PostHandleEvent, inputs will // be selected only when focused via a key or when the navigation // flag is used and we want to select the text on label clicks as // well. nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content); fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS); } // Dispatch a new click event to |content| // (For compatibility with IE, we do only left click. If // we wanted to interpret the HTML spec very narrowly, we // would do nothing. If we wanted to do something // sensible, we might send more events through like // this.) See bug 7554, bug 49897, and bug 96813. nsEventStatus status = aVisitor.mEventStatus; // Ok to use aVisitor.mEvent as parameter because DispatchClickEvent // will actually create a new event. widget::EventFlags eventFlags; eventFlags.Clear(); eventFlags.mMultipleActionsPrevented = true; DispatchClickEvent(aVisitor.mPresContext, static_cast<nsInputEvent*>(aVisitor.mEvent), content, false, &eventFlags, &status); // Do we care about the status this returned? I don't think we do... // Don't run another <label> off of this click aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; } break; } mHandlingEvent = false; } return NS_OK; }
NS_IMETHODIMP nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } switch (aEvent->message) { case NS_KEY_DOWN: if (NS_KEY_EVENT == aEvent->eventStructType) { nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent; if (NS_VK_SPACE == keyEvent->keyCode) { nsEventStateManager *esm = aPresContext->EventStateManager(); // :hover:active state esm->SetContentState(mContent, NS_EVENT_STATE_HOVER); esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE); } } break; // On mac, Return fires the defualt button, not the focused one. #ifndef XP_MACOSX case NS_KEY_PRESS: if (NS_KEY_EVENT == aEvent->eventStructType) { nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent; if (NS_VK_RETURN == keyEvent->keyCode) { nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent)); if (buttonEl) { MouseClicked(aPresContext, aEvent); *aEventStatus = nsEventStatus_eConsumeNoDefault; } } } break; #endif case NS_KEY_UP: if (NS_KEY_EVENT == aEvent->eventStructType) { nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent; if (NS_VK_SPACE == keyEvent->keyCode) { // only activate on keyup if we're already in the :hover:active state NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); nsEventStates buttonState = mContent->AsElement()->State(); if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) { // return to normal state nsEventStateManager *esm = aPresContext->EventStateManager(); esm->SetContentState(nsnull, NS_EVENT_STATE_ACTIVE); esm->SetContentState(nsnull, NS_EVENT_STATE_HOVER); MouseClicked(aPresContext, aEvent); } } } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aEvent)) { MouseClicked(aPresContext, aEvent); } break; } return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); }
NS_IMETHODIMP nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } PRBool doDefault = PR_TRUE; switch (aEvent->message) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { // titlebar has no effect in non-chrome shells nsCOMPtr<nsISupports> cont = aPresContext->GetContainer(); nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont); if (dsti) { PRInt32 type = -1; if (NS_SUCCEEDED(dsti->GetItemType(&type)) && type == nsIDocShellTreeItem::typeChrome) { // we're tracking. mTrackingMouseMove = PR_TRUE; // start capture. CaptureMouseEvents(aPresContext,PR_TRUE); // remember current mouse coordinates. mLastPoint = aEvent->refPoint; } } *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_BUTTON_UP: { if(mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { // we're done tracking. mTrackingMouseMove = PR_FALSE; // end capture CaptureMouseEvents(aPresContext,PR_FALSE); *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_MOVE: { if(mTrackingMouseMove) { nsIntPoint nsMoveBy = aEvent->refPoint - mLastPoint; nsIFrame* parent = GetParent(); while (parent && parent->GetType() != nsGkAtoms::menuPopupFrame) parent = parent->GetParent(); // if the titlebar is in a popup, move the popup's widget, otherwise // move the widget associated with the window if (parent) { nsCOMPtr<nsIWidget> widget; (static_cast<nsMenuPopupFrame*>(parent))-> GetWidget(getter_AddRefs(widget)); nsIntRect bounds; widget->GetScreenBounds(bounds); widget->Move(bounds.x + nsMoveBy.x, bounds.y + nsMoveBy.y); } else { nsIPresShell* presShell = aPresContext->PresShell(); nsPIDOMWindow *window = presShell->GetDocument()->GetWindow(); if (window) { window->MoveBy(nsMoveBy.x, nsMoveBy.y); } } *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aEvent)) { MouseClicked(aPresContext, aEvent); } break; } if ( doDefault ) return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); else return NS_OK; }
nsresult HTMLButtonElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) { nsresult rv = NS_OK; if (!aVisitor.mPresContext) { return rv; } if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault && NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) { nsUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted, NS_UI_ACTIVATE, 1); nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell(); if (shell) { nsEventStatus status = nsEventStatus_eIgnore; mInInternalActivate = true; shell->HandleDOMEventWithTarget(this, &actEvent, &status); mInInternalActivate = false; // If activate is cancelled, we must do the same as when click is // cancelled (revert the checkbox to its original value). if (status == nsEventStatus_eConsumeNoDefault) aVisitor.mEventStatus = status; } } // mForm is null if the event handler removed us from the document (bug 194582). if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // tell the form that we are about to exit a click handler // so the form knows not to defer subsequent submissions // the pending ones that were created during the handler // will be flushed or forgoten. mForm->OnSubmitClickEnd(); } if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { switch (aVisitor.mEvent->message) { case NS_KEY_PRESS: case NS_KEY_UP: { // For backwards compat, trigger buttons with space or enter // (bug 25300) nsKeyEvent * keyEvent = (nsKeyEvent *)aVisitor.mEvent; if ((keyEvent->keyCode == NS_VK_RETURN && NS_KEY_PRESS == aVisitor.mEvent->message) || (keyEvent->keyCode == NS_VK_SPACE && NS_KEY_UP == aVisitor.mEvent->message)) { nsEventStatus status = nsEventStatus_eIgnore; nsMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK, nullptr, nsMouseEvent::eReal); event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), aVisitor.mPresContext, &event, nullptr, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break;// NS_KEY_PRESS case NS_MOUSE_BUTTON_DOWN: { if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT) { if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eLeftButton) { if (aVisitor.mEvent->mFlags.mIsTrusted) { nsEventStateManager* esm = aVisitor.mPresContext->EventStateManager(); nsEventStateManager::SetActiveManager( static_cast<nsEventStateManager*>(esm), this); } nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) fm->SetFocus(this, nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL); aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; } else if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eMiddleButton || static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eRightButton) { // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? if (aVisitor.mDOMEvent) { aVisitor.mDOMEvent->StopPropagation(); } } } } break; // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? case NS_MOUSE_BUTTON_UP: case NS_MOUSE_DOUBLECLICK: { if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT && aVisitor.mDOMEvent && (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eMiddleButton || static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eRightButton)) { aVisitor.mDOMEvent->StopPropagation(); } } break; case NS_MOUSE_ENTER_SYNTH: { aVisitor.mPresContext->EventStateManager()-> SetContentState(this, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; // XXX this doesn't seem to do anything yet case NS_MOUSE_EXIT_SYNTH: { aVisitor.mPresContext->EventStateManager()-> SetContentState(nullptr, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; default: break; } if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) { if (mForm && (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) { nsFormEvent event(true, (mType == NS_FORM_BUTTON_RESET) ? NS_FORM_RESET : NS_FORM_SUBMIT); event.originator = this; nsEventStatus status = nsEventStatus_eIgnore; nsCOMPtr<nsIPresShell> presShell = aVisitor.mPresContext->GetPresShell(); // If |nsIPresShell::Destroy| has been called due to // handling the event, the pres context will return // a null pres shell. See bug 125624. // // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. if (presShell && (event.message != NS_FORM_SUBMIT || mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) || mForm->CheckValidFormSubmission())) { // TODO: removing this code and have the submit event sent by the form // see bug 592124. // Hold a strong ref while dispatching nsRefPtr<nsHTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(mForm, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // Tell the form to flush a possible pending submission. // the reason is that the script returned false (the event was // not ignored) so if there is a stored submission, it needs to // be submitted immediatelly. // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event. mForm->FlushPendingSubmission(); } //if return rv; }
NS_IMETHODIMP nsResizerFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } nsWeakFrame weakFrame(this); PRBool doDefault = PR_TRUE; switch (aEvent->message) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsIContent* contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (!frameToResize) break; mMouseDownRect = frameToResize->GetScreenRect(); } else { // ask the widget implementation to begin a resize drag if it can Direction direction = GetDirection(); nsresult rv = aEvent->widget->BeginResizeDrag(aEvent, direction.mHorizontal, direction.mVertical); if (rv == NS_ERROR_NOT_IMPLEMENTED && window) { // if there's no native resize support, we need to do window // resizing ourselves window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y, &mMouseDownRect.width, &mMouseDownRect.height); } else { // for native drags, don't set the fields below doDefault = PR_FALSE; break; } } // we're tracking mTrackingMouseMove = PR_TRUE; // remember current mouse coordinates mMouseDownPoint = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset(); nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); doDefault = PR_FALSE; } } break; case NS_MOUSE_BUTTON_UP: { if (mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { // we're done tracking. mTrackingMouseMove = PR_FALSE; nsIPresShell::SetCapturingContent(nsnull, 0); doDefault = PR_FALSE; } } break; case NS_MOUSE_MOVE: { if (mTrackingMouseMove) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsCOMPtr<nsIContent> contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); // check if the returned content really is a menupopup nsMenuPopupFrame* menuPopupFrame = nsnull; if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (frameToResize && frameToResize->GetType() == nsGkAtoms::menuPopupFrame) { menuPopupFrame = static_cast<nsMenuPopupFrame *>(frameToResize); } } // both MouseMove and direction are negative when pointing to the // top and left, and positive when pointing to the bottom and right // retrieve the offset of the mousemove event relative to the mousedown. // The difference is how much the resize needs to be nsIntPoint screenPoint(aEvent->refPoint + aEvent->widget->WidgetToScreenOffset()); nsIntPoint mouseMove(screenPoint - mMouseDownPoint); // what direction should we go in? For content resizing, always use // 'bottomend'. For other windows, check the dir attribute. Direction direction; if (window || menuPopupFrame) { direction = GetDirection(); if (menuPopupFrame) { menuPopupFrame->CanAdjustEdges( (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT, (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove); } } else if (contentToResize) { direction.mHorizontal = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL ? -1 : 1; direction.mVertical = 1; } else { break; // don't do anything if there's nothing to resize } nsIntRect rect = mMouseDownRect; AdjustDimensions(&rect.x, &rect.width, mouseMove.x, direction.mHorizontal); AdjustDimensions(&rect.y, &rect.height, mouseMove.y, direction.mVertical); // Don't allow resizing a window or a popup past the edge of the screen, // so adjust the rectangle to fit within the available screen area. if (window) { nsCOMPtr<nsIScreen> screen; nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1")); if (sm) { nsIntRect frameRect = GetScreenRect(); sm->ScreenForRect(frameRect.x, frameRect.y, 1, 1, getter_AddRefs(screen)); if (screen) { nsIntRect screenRect; screen->GetRect(&screenRect.x, &screenRect.y, &screenRect.width, &screenRect.height); rect.IntersectRect(rect, screenRect); } } } else if (menuPopupFrame) { nsPoint framePoint = menuPopupFrame->GetScreenRectInAppUnits().TopLeft(); nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame(); nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); nsRect screenRect = menuPopupFrame->GetConstraintRect(framePoint, rootScreenRect); // round using ToInsidePixels as it's better to be a pixel too small // than be too large. If the popup is too large it could get flipped // to the opposite side of the anchor point while resizing. nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel()); rect.IntersectRect(rect, screenRectPixels); } if (contentToResize) { nsIntRect cssRect = rect.ToAppUnits(aPresContext->AppUnitsPerDevPixel()) .ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); nsAutoString widthstr, heightstr; widthstr.AppendInt(cssRect.width); heightstr.AppendInt(cssRect.height); // for XUL elements, just set the width and height attributes. For // other elements, set style.width and style.height if (contentToResize->IsXUL()) { nsIntRect oldRect; nsWeakFrame weakFrame(menuPopupFrame); if (menuPopupFrame) { nsCOMPtr<nsIWidget> widget; menuPopupFrame->GetWidget(getter_AddRefs(widget)); if (widget) widget->GetScreenBounds(oldRect); } contentToResize->SetAttr(kNameSpaceID_None, nsGkAtoms::width, widthstr, PR_TRUE); contentToResize->SetAttr(kNameSpaceID_None, nsGkAtoms::height, heightstr, PR_TRUE); if (weakFrame.IsAlive() && (oldRect.x != rect.x || oldRect.y != rect.y)) { // XXX This might go very wrong, since menu popups may add // offsets (e.g. from margins) to this position, so the popup's // widget won't end up at the desired position. menuPopupFrame->MoveTo(rect.x, rect.y, PR_TRUE); } } else { nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyleContent = do_QueryInterface(contentToResize); if (inlineStyleContent) { widthstr += NS_LITERAL_STRING("px"); heightstr += NS_LITERAL_STRING("px"); nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; inlineStyleContent->GetStyle(getter_AddRefs(decl)); decl->SetProperty(NS_LITERAL_STRING("width"), widthstr, EmptyString()); decl->SetProperty(NS_LITERAL_STRING("height"), heightstr, EmptyString()); } } } else { window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, PR_TRUE); // do the repaint. } doDefault = PR_FALSE; } } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aEvent)) { MouseClicked(aPresContext, aEvent); } break; } if (!doDefault) *aEventStatus = nsEventStatus_eConsumeNoDefault; if (doDefault && weakFrame.IsAlive()) return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); else return NS_OK; }
NS_IMETHODIMP nsResizerFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } nsWeakFrame weakFrame(this); bool doDefault = true; switch (aEvent->message) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsIContent* contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (!frameToResize) break; // cache the content rectangle for the frame to resize // GetScreenRectInAppUnits returns the border box rectangle, so // adjust to get the desired content rectangle. nsRect rect = frameToResize->GetScreenRectInAppUnits(); switch (frameToResize->GetStylePosition()->mBoxSizing) { case NS_STYLE_BOX_SIZING_CONTENT: rect.Deflate(frameToResize->GetUsedPadding()); case NS_STYLE_BOX_SIZING_PADDING: rect.Deflate(frameToResize->GetUsedBorder()); default: break; } mMouseDownRect = rect.ToNearestPixels(aPresContext->AppUnitsPerDevPixel()); doDefault = false; } else { // If there is no window, then resizing isn't allowed. if (!window) break; doDefault = false; // ask the widget implementation to begin a resize drag if it can Direction direction = GetDirection(); nsresult rv = aEvent->widget->BeginResizeDrag(aEvent, direction.mHorizontal, direction.mVertical); // for native drags, don't set the fields below if (rv != NS_ERROR_NOT_IMPLEMENTED) break; // if there's no native resize support, we need to do window // resizing ourselves window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y, &mMouseDownRect.width, &mMouseDownRect.height); } // we're tracking mTrackingMouseMove = true; // remember current mouse coordinates mMouseDownPoint = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset(); nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); } } break; case NS_MOUSE_BUTTON_UP: { if (mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { // we're done tracking. mTrackingMouseMove = false; nsIPresShell::SetCapturingContent(nsnull, 0); doDefault = false; } } break; case NS_MOUSE_MOVE: { if (mTrackingMouseMove) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsCOMPtr<nsIContent> contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); // check if the returned content really is a menupopup nsMenuPopupFrame* menuPopupFrame = nsnull; if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (frameToResize && frameToResize->GetType() == nsGkAtoms::menuPopupFrame) { menuPopupFrame = static_cast<nsMenuPopupFrame *>(frameToResize); } } // both MouseMove and direction are negative when pointing to the // top and left, and positive when pointing to the bottom and right // retrieve the offset of the mousemove event relative to the mousedown. // The difference is how much the resize needs to be nsIntPoint screenPoint(aEvent->refPoint + aEvent->widget->WidgetToScreenOffset()); nsIntPoint mouseMove(screenPoint - mMouseDownPoint); // Determine which direction to resize by checking the dir attribute. // For windows and menus, ensure that it can be resized in that direction. Direction direction = GetDirection(); if (window || menuPopupFrame) { if (menuPopupFrame) { menuPopupFrame->CanAdjustEdges( (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT, (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove); } } else if (!contentToResize) { break; // don't do anything if there's nothing to resize } nsIntRect rect = mMouseDownRect; AdjustDimensions(&rect.x, &rect.width, mouseMove.x, direction.mHorizontal); AdjustDimensions(&rect.y, &rect.height, mouseMove.y, direction.mVertical); // Don't allow resizing a window or a popup past the edge of the screen, // so adjust the rectangle to fit within the available screen area. if (window) { nsCOMPtr<nsIScreen> screen; nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1")); if (sm) { nsIntRect frameRect = GetScreenRect(); sm->ScreenForRect(frameRect.x, frameRect.y, 1, 1, getter_AddRefs(screen)); if (screen) { nsIntRect screenRect; screen->GetRect(&screenRect.x, &screenRect.y, &screenRect.width, &screenRect.height); rect.IntersectRect(rect, screenRect); } } } else if (menuPopupFrame) { nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits(); nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame(); nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect); // round using ToInsidePixels as it's better to be a pixel too small // than be too large. If the popup is too large it could get flipped // to the opposite side of the anchor point while resizing. nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel()); rect.IntersectRect(rect, screenRectPixels); } if (contentToResize) { // convert the rectangle into css pixels. When changing the size in a // direction, don't allow the new size to be less that the resizer's // size. This ensures that content isn't resized too small as to make // the resizer invisible. nsRect appUnitsRect = rect.ToAppUnits(aPresContext->AppUnitsPerDevPixel()); if (appUnitsRect.width < mRect.width && mouseMove.x) appUnitsRect.width = mRect.width; if (appUnitsRect.height < mRect.height && mouseMove.y) appUnitsRect.height = mRect.height; nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); nsIntRect oldRect; nsWeakFrame weakFrame(menuPopupFrame); if (menuPopupFrame) { nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); if (widget) widget->GetScreenBounds(oldRect); // convert the new rectangle into outer window coordinates nsIntPoint clientOffset = widget->GetClientOffset(); rect.x -= clientOffset.x; rect.y -= clientOffset.y; } SizeInfo sizeInfo, originalSizeInfo; sizeInfo.width.AppendInt(cssRect.width); sizeInfo.height.AppendInt(cssRect.height); ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo); MaybePersistOriginalSize(contentToResize, originalSizeInfo); if (weakFrame.IsAlive() && (oldRect.x != rect.x || oldRect.y != rect.y) && (!menuPopupFrame->IsAnchored() || menuPopupFrame->PopupLevel() != ePopupLevelParent)) { menuPopupFrame->MoveTo(rect.x, rect.y, true); } } else { window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint. } doDefault = false; } } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aEvent)) { MouseClicked(aPresContext, aEvent); } break; case NS_MOUSE_DOUBLECLICK: if (aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsIContent* contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (frameToResize && frameToResize->GetType() == nsGkAtoms::menuPopupFrame) break; // Don't restore original sizing for menupopup frames until // we handle screen constraints here. (Bug 357725) RestoreOriginalSize(contentToResize); } } break; } if (!doDefault) *aEventStatus = nsEventStatus_eConsumeNoDefault; if (doDefault && weakFrame.IsAlive()) return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); return NS_OK; }
NS_IMETHODIMP nsResizerFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { nsWeakFrame weakFrame(this); PRBool doDefault = PR_TRUE; switch (aEvent->message) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { nsresult rv = NS_OK; // what direction should we go in? // convert eDirection to horizontal and vertical directions static const PRInt8 directions[][2] = { {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1} }; // ask the widget implementation to begin a resize drag if it can rv = aEvent->widget->BeginResizeDrag(aEvent, directions[mDirection][0], directions[mDirection][1]); if (rv == NS_ERROR_NOT_IMPLEMENTED) { // there's no native resize support, // we need to window resizing ourselves // we're tracking. mTrackingMouseMove = PR_TRUE; // start capture. aEvent->widget->CaptureMouse(PR_TRUE); CaptureMouseEvents(aPresContext,PR_TRUE); // remember current mouse coordinates. mLastPoint = aEvent->refPoint; aEvent->widget->GetScreenBounds(mWidgetRect); } *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_BUTTON_UP: { if(mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) { // we're done tracking. mTrackingMouseMove = PR_FALSE; // end capture aEvent->widget->CaptureMouse(PR_FALSE); CaptureMouseEvents(aPresContext,PR_FALSE); *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_MOVE: { if(mTrackingMouseMove) { // get the document and the window - should this be cached? nsPIDOMWindow *domWindow = aPresContext->PresShell()->GetDocument()->GetWindow(); NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = do_QueryInterface(domWindow->GetDocShell()); NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); nsCOMPtr<nsIDocShellTreeOwner> treeOwner; docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); nsCOMPtr<nsIBaseWindow> window(do_QueryInterface(treeOwner)); if (!window) { return NS_OK; } nsPoint nsMoveBy(0,0),nsSizeBy(0,0); nsPoint nsMouseMove(aEvent->refPoint - mLastPoint); switch(mDirection) { case topleft: nsMoveBy = nsMouseMove; nsSizeBy -= nsMouseMove; break; case top: nsMoveBy.y = nsMouseMove.y; nsSizeBy.y = - nsMouseMove.y; break; case topright: nsMoveBy.y = nsMouseMove.y; nsSizeBy.x = nsMouseMove.x; mLastPoint.x += nsMouseMove.x; nsSizeBy.y = -nsMouseMove.y; break; case left: nsMoveBy.x = nsMouseMove.x; nsSizeBy.x = -nsMouseMove.x; break; case right: nsSizeBy.x = nsMouseMove.x; mLastPoint.x += nsMouseMove.x; break; case bottomleft: nsMoveBy.x = nsMouseMove.x; nsSizeBy.y = nsMouseMove.y; nsSizeBy.x = -nsMouseMove.x; mLastPoint.y += nsMouseMove.y; break; case bottom: nsSizeBy.y = nsMouseMove.y; mLastPoint.y += nsMouseMove.y; break; case bottomright: nsSizeBy = nsMouseMove; mLastPoint += nsMouseMove; break; } PRInt32 x,y,cx,cy; window->GetPositionAndSize(&x,&y,&cx,&cy); x+=nsMoveBy.x; y+=nsMoveBy.y; cx+=nsSizeBy.x; cy+=nsSizeBy.y; window->SetPositionAndSize(x,y,cx,cy,PR_TRUE); // do the repaint. /* if(nsSizeBy.x || nsSizeBy.y) { window->ResizeBy(nsSizeBy.x,nsSizeBy.y); } if(nsMoveBy.x || nsMoveBy.y) { window->MoveBy(nsMoveBy.x,nsMoveBy.y); } */ *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = PR_FALSE; } } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aEvent)) { MouseClicked(aPresContext, aEvent); } break; } if (doDefault && weakFrame.IsAlive()) return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); else return NS_OK; }