michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nsCOMPtr.h" michael@0: #include "nsButtonBoxFrame.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIDOMNodeList.h" michael@0: #include "nsIDOMXULButtonElement.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsContentUtils.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/EventStateManager.h" michael@0: #include "mozilla/EventStates.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/TextEvents.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // michael@0: // NS_NewXULButtonFrame michael@0: // michael@0: // Creates a new Button frame and returns it michael@0: // michael@0: nsIFrame* michael@0: NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsButtonBoxFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame) michael@0: michael@0: void michael@0: nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // override, since we don't want children to get events michael@0: if (aBuilder->IsForEventDelivery()) michael@0: return; michael@0: nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); michael@0: } michael@0: michael@0: nsresult michael@0: nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, michael@0: WidgetGUIEvent* aEvent, michael@0: nsEventStatus* aEventStatus) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEventStatus); michael@0: if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: switch (aEvent->message) { michael@0: case NS_KEY_DOWN: { michael@0: WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); michael@0: if (!keyEvent) { michael@0: break; michael@0: } michael@0: if (NS_VK_SPACE == keyEvent->keyCode) { michael@0: EventStateManager* esm = aPresContext->EventStateManager(); michael@0: // :hover:active state michael@0: esm->SetContentState(mContent, NS_EVENT_STATE_HOVER); michael@0: esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: // On mac, Return fires the default button, not the focused one. michael@0: #ifndef XP_MACOSX michael@0: case NS_KEY_PRESS: { michael@0: WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); michael@0: if (!keyEvent) { michael@0: break; michael@0: } michael@0: if (NS_VK_RETURN == keyEvent->keyCode) { michael@0: nsCOMPtr buttonEl(do_QueryInterface(mContent)); michael@0: if (buttonEl) { michael@0: MouseClicked(aPresContext, aEvent); michael@0: *aEventStatus = nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: #endif michael@0: michael@0: case NS_KEY_UP: { michael@0: WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); michael@0: if (!keyEvent) { michael@0: break; michael@0: } michael@0: if (NS_VK_SPACE == keyEvent->keyCode) { michael@0: // only activate on keyup if we're already in the :hover:active state michael@0: NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); michael@0: EventStates buttonState = mContent->AsElement()->State(); michael@0: if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE | michael@0: NS_EVENT_STATE_HOVER)) { michael@0: // return to normal state michael@0: EventStateManager* esm = aPresContext->EventStateManager(); michael@0: esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); michael@0: esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); michael@0: MouseClicked(aPresContext, aEvent); michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case NS_MOUSE_CLICK: { michael@0: WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); michael@0: if (mouseEvent->IsLeftClickEvent()) { michael@0: MouseClicked(aPresContext, mouseEvent); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); michael@0: } michael@0: michael@0: void michael@0: nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent) michael@0: { michael@0: // Don't execute if we're disabled. michael@0: if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, michael@0: nsGkAtoms::_true, eCaseMatters)) michael@0: return; michael@0: michael@0: // Execute the oncommand event handler. michael@0: bool isShift = false; michael@0: bool isControl = false; michael@0: bool isAlt = false; michael@0: bool isMeta = false; michael@0: if(aEvent) { michael@0: WidgetInputEvent* inputEvent = aEvent->AsInputEvent(); michael@0: isShift = inputEvent->IsShift(); michael@0: isControl = inputEvent->IsControl(); michael@0: isAlt = inputEvent->IsAlt(); michael@0: isMeta = inputEvent->IsMeta(); michael@0: } michael@0: michael@0: // Have the content handle the event, propagating it according to normal DOM rules. michael@0: nsCOMPtr shell = PresContext()->GetPresShell(); michael@0: if (shell) { michael@0: nsContentUtils::DispatchXULCommand(mContent, michael@0: aEvent ? michael@0: aEvent->mFlags.mIsTrusted : aTrustEvent, michael@0: nullptr, shell, michael@0: isControl, isAlt, isShift, isMeta); michael@0: } michael@0: }