Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
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/. */
6 #include "nsCOMPtr.h"
7 #include "nsPresContext.h"
8 #include "nsGkAtoms.h"
9 #include "nsButtonBoxFrame.h"
10 #include "nsITimer.h"
11 #include "nsRepeatService.h"
12 #include "mozilla/MouseEvents.h"
13 #include "nsIContent.h"
15 using namespace mozilla;
17 class nsAutoRepeatBoxFrame : public nsButtonBoxFrame
18 {
19 public:
20 NS_DECL_FRAMEARENA_HELPERS
22 friend nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell,
23 nsStyleContext* aContext);
25 virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
27 virtual nsresult AttributeChanged(int32_t aNameSpaceID,
28 nsIAtom* aAttribute,
29 int32_t aModType) MOZ_OVERRIDE;
31 virtual nsresult HandleEvent(nsPresContext* aPresContext,
32 WidgetGUIEvent* aEvent,
33 nsEventStatus* aEventStatus) MOZ_OVERRIDE;
35 NS_IMETHOD HandlePress(nsPresContext* aPresContext,
36 WidgetGUIEvent* aEvent,
37 nsEventStatus* aEventStatus) MOZ_OVERRIDE;
39 NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
40 WidgetGUIEvent* aEvent,
41 nsEventStatus* aEventStatus) MOZ_OVERRIDE;
43 protected:
44 nsAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext):
45 nsButtonBoxFrame(aPresShell, aContext) {}
47 void StartRepeat() {
48 if (IsActivatedOnHover()) {
49 // No initial delay on hover.
50 nsRepeatService::GetInstance()->Start(Notify, this, 0);
51 } else {
52 nsRepeatService::GetInstance()->Start(Notify, this);
53 }
54 }
55 void StopRepeat() {
56 nsRepeatService::GetInstance()->Stop(Notify, this);
57 }
58 void Notify();
59 static void Notify(void* aData) {
60 static_cast<nsAutoRepeatBoxFrame*>(aData)->Notify();
61 }
63 bool mTrustedEvent;
65 bool IsActivatedOnHover();
66 };
68 nsIFrame*
69 NS_NewAutoRepeatBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
70 {
71 return new (aPresShell) nsAutoRepeatBoxFrame (aPresShell, aContext);
72 }
74 NS_IMPL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame)
76 nsresult
77 nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext,
78 WidgetGUIEvent* aEvent,
79 nsEventStatus* aEventStatus)
80 {
81 NS_ENSURE_ARG_POINTER(aEventStatus);
82 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
83 return NS_OK;
84 }
86 switch(aEvent->message)
87 {
88 // repeat mode may be "hover" for repeating while the mouse is hovering
89 // over the element, otherwise repetition is done while the element is
90 // active (pressed).
91 case NS_MOUSE_ENTER:
92 case NS_MOUSE_ENTER_SYNTH:
93 if (IsActivatedOnHover()) {
94 StartRepeat();
95 mTrustedEvent = aEvent->mFlags.mIsTrusted;
96 }
97 break;
99 case NS_MOUSE_EXIT:
100 case NS_MOUSE_EXIT_SYNTH:
101 // always stop on mouse exit
102 StopRepeat();
103 // Not really necessary but do this to be safe
104 mTrustedEvent = false;
105 break;
107 case NS_MOUSE_CLICK: {
108 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
109 if (mouseEvent->IsLeftClickEvent()) {
110 // skip button frame handling to prevent click handling
111 return nsBoxFrame::HandleEvent(aPresContext, mouseEvent, aEventStatus);
112 }
113 break;
114 }
115 }
117 return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
118 }
120 NS_IMETHODIMP
121 nsAutoRepeatBoxFrame::HandlePress(nsPresContext* aPresContext,
122 WidgetGUIEvent* aEvent,
123 nsEventStatus* aEventStatus)
124 {
125 if (!IsActivatedOnHover()) {
126 StartRepeat();
127 mTrustedEvent = aEvent->mFlags.mIsTrusted;
128 DoMouseClick(aEvent, mTrustedEvent);
129 }
131 return NS_OK;
132 }
134 NS_IMETHODIMP
135 nsAutoRepeatBoxFrame::HandleRelease(nsPresContext* aPresContext,
136 WidgetGUIEvent* aEvent,
137 nsEventStatus* aEventStatus)
138 {
139 if (!IsActivatedOnHover()) {
140 StopRepeat();
141 }
142 return NS_OK;
143 }
145 nsresult
146 nsAutoRepeatBoxFrame::AttributeChanged(int32_t aNameSpaceID,
147 nsIAtom* aAttribute,
148 int32_t aModType)
149 {
150 if (aAttribute == nsGkAtoms::type) {
151 StopRepeat();
152 }
153 return NS_OK;
154 }
156 void
157 nsAutoRepeatBoxFrame::Notify()
158 {
159 DoMouseClick(nullptr, mTrustedEvent);
160 }
162 void
163 nsAutoRepeatBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
164 {
165 // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
166 // from under you while you're in the process of scrolling.
167 StopRepeat();
168 nsButtonBoxFrame::DestroyFrom(aDestructRoot);
169 }
171 bool
172 nsAutoRepeatBoxFrame::IsActivatedOnHover()
173 {
174 return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::repeat,
175 nsGkAtoms::hover, eCaseMatters);
176 }