nsButtonBoxFrame.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsCOMPtr.h"
  6. #include "nsButtonBoxFrame.h"
  7. #include "nsIContent.h"
  8. #include "nsIDOMNodeList.h"
  9. #include "nsIDOMXULButtonElement.h"
  10. #include "nsGkAtoms.h"
  11. #include "nsNameSpaceManager.h"
  12. #include "nsPresContext.h"
  13. #include "nsIPresShell.h"
  14. #include "nsIDOMElement.h"
  15. #include "nsIDOMEvent.h"
  16. #include "nsDisplayList.h"
  17. #include "nsContentUtils.h"
  18. #include "mozilla/dom/Element.h"
  19. #include "mozilla/EventStateManager.h"
  20. #include "mozilla/EventStates.h"
  21. #include "mozilla/MouseEvents.h"
  22. #include "mozilla/TextEvents.h"
  23. using namespace mozilla;
  24. NS_IMPL_ISUPPORTS(nsButtonBoxFrame::nsButtonBoxListener, nsIDOMEventListener)
  25. nsresult
  26. nsButtonBoxFrame::nsButtonBoxListener::HandleEvent(nsIDOMEvent* aEvent)
  27. {
  28. if (!mButtonBoxFrame) {
  29. return NS_OK;
  30. }
  31. nsAutoString eventType;
  32. aEvent->GetType(eventType);
  33. if (eventType.EqualsLiteral("blur")) {
  34. mButtonBoxFrame->Blurred();
  35. return NS_OK;
  36. }
  37. NS_ABORT();
  38. return NS_OK;
  39. }
  40. //
  41. // NS_NewXULButtonFrame
  42. //
  43. // Creates a new Button frame and returns it
  44. //
  45. nsIFrame*
  46. NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
  47. {
  48. return new (aPresShell) nsButtonBoxFrame(aContext);
  49. }
  50. NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame)
  51. nsButtonBoxFrame::nsButtonBoxFrame(nsStyleContext* aContext) :
  52. nsBoxFrame(aContext, false),
  53. mButtonBoxListener(nullptr),
  54. mIsHandlingKeyEvent(false)
  55. {
  56. UpdateMouseThrough();
  57. }
  58. void
  59. nsButtonBoxFrame::Init(nsIContent* aContent,
  60. nsContainerFrame* aParent,
  61. nsIFrame* aPrevInFlow)
  62. {
  63. nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
  64. mButtonBoxListener = new nsButtonBoxListener(this);
  65. mContent->AddSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
  66. }
  67. void
  68. nsButtonBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
  69. {
  70. mContent->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
  71. mButtonBoxListener->mButtonBoxFrame = nullptr;
  72. mButtonBoxListener = nullptr;
  73. nsBoxFrame::DestroyFrom(aDestructRoot);
  74. }
  75. void
  76. nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
  77. const nsDisplayListSet& aLists)
  78. {
  79. // override, since we don't want children to get events
  80. if (aBuilder->IsForEventDelivery())
  81. return;
  82. nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists);
  83. }
  84. nsresult
  85. nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext,
  86. WidgetGUIEvent* aEvent,
  87. nsEventStatus* aEventStatus)
  88. {
  89. NS_ENSURE_ARG_POINTER(aEventStatus);
  90. if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
  91. return NS_OK;
  92. }
  93. switch (aEvent->mMessage) {
  94. case eKeyDown: {
  95. WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
  96. if (!keyEvent) {
  97. break;
  98. }
  99. if (NS_VK_SPACE == keyEvent->mKeyCode) {
  100. EventStateManager* esm = aPresContext->EventStateManager();
  101. // :hover:active state
  102. esm->SetContentState(mContent, NS_EVENT_STATE_HOVER);
  103. esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE);
  104. mIsHandlingKeyEvent = true;
  105. }
  106. break;
  107. }
  108. case eKeyPress: {
  109. WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
  110. if (!keyEvent) {
  111. break;
  112. }
  113. if (NS_VK_RETURN == keyEvent->mKeyCode) {
  114. nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent));
  115. if (buttonEl) {
  116. MouseClicked(aEvent);
  117. *aEventStatus = nsEventStatus_eConsumeNoDefault;
  118. }
  119. }
  120. break;
  121. }
  122. case eKeyUp: {
  123. WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
  124. if (!keyEvent) {
  125. break;
  126. }
  127. if (NS_VK_SPACE == keyEvent->mKeyCode) {
  128. mIsHandlingKeyEvent = false;
  129. // only activate on keyup if we're already in the :hover:active state
  130. NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
  131. EventStates buttonState = mContent->AsElement()->State();
  132. if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
  133. NS_EVENT_STATE_HOVER)) {
  134. // return to normal state
  135. EventStateManager* esm = aPresContext->EventStateManager();
  136. esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
  137. esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
  138. MouseClicked(aEvent);
  139. }
  140. }
  141. break;
  142. }
  143. case eMouseClick: {
  144. WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  145. if (mouseEvent->IsLeftClickEvent()) {
  146. MouseClicked(mouseEvent);
  147. }
  148. break;
  149. }
  150. default:
  151. break;
  152. }
  153. return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
  154. }
  155. void
  156. nsButtonBoxFrame::Blurred()
  157. {
  158. NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
  159. EventStates buttonState = mContent->AsElement()->State();
  160. if (mIsHandlingKeyEvent &&
  161. buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
  162. NS_EVENT_STATE_HOVER)) {
  163. // return to normal state
  164. EventStateManager* esm = PresContext()->EventStateManager();
  165. esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
  166. esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
  167. }
  168. mIsHandlingKeyEvent = false;
  169. }
  170. void
  171. nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent)
  172. {
  173. // Don't execute if we're disabled.
  174. if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
  175. nsGkAtoms::_true, eCaseMatters))
  176. return;
  177. // Execute the oncommand event handler.
  178. bool isShift = false;
  179. bool isControl = false;
  180. bool isAlt = false;
  181. bool isMeta = false;
  182. if(aEvent) {
  183. WidgetInputEvent* inputEvent = aEvent->AsInputEvent();
  184. isShift = inputEvent->IsShift();
  185. isControl = inputEvent->IsControl();
  186. isAlt = inputEvent->IsAlt();
  187. isMeta = inputEvent->IsMeta();
  188. }
  189. // Have the content handle the event, propagating it according to normal DOM rules.
  190. nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
  191. if (shell) {
  192. nsContentUtils::DispatchXULCommand(mContent,
  193. aEvent ?
  194. aEvent->IsTrusted() : aTrustEvent,
  195. nullptr, shell,
  196. isControl, isAlt, isShift, isMeta);
  197. }
  198. }