Line data Source 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/. */
5 :
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"
14 :
15 : using namespace mozilla;
16 :
17 0 : class nsAutoRepeatBoxFrame final : public nsButtonBoxFrame
18 : {
19 : public:
20 0 : NS_DECL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame)
21 :
22 : friend nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell,
23 : nsStyleContext* aContext);
24 :
25 : virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
26 :
27 : virtual nsresult AttributeChanged(int32_t aNameSpaceID,
28 : nsIAtom* aAttribute,
29 : int32_t aModType) override;
30 :
31 : virtual nsresult HandleEvent(nsPresContext* aPresContext,
32 : WidgetGUIEvent* aEvent,
33 : nsEventStatus* aEventStatus) override;
34 :
35 : NS_IMETHOD HandlePress(nsPresContext* aPresContext,
36 : WidgetGUIEvent* aEvent,
37 : nsEventStatus* aEventStatus) override;
38 :
39 : NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
40 : WidgetGUIEvent* aEvent,
41 : nsEventStatus* aEventStatus) override;
42 :
43 : protected:
44 0 : explicit nsAutoRepeatBoxFrame(nsStyleContext* aContext):
45 0 : nsButtonBoxFrame(aContext, kClassID) {}
46 :
47 0 : void StartRepeat() {
48 0 : if (IsActivatedOnHover()) {
49 : // No initial delay on hover.
50 0 : nsRepeatService::GetInstance()->Start(Notify, this,
51 0 : mContent->OwnerDoc(),
52 0 : NS_LITERAL_CSTRING("DoMouseClick"),
53 0 : 0);
54 : } else {
55 0 : nsRepeatService::GetInstance()->Start(Notify, this,
56 0 : mContent->OwnerDoc(),
57 0 : NS_LITERAL_CSTRING("DoMouseClick"));
58 : }
59 0 : }
60 0 : void StopRepeat() {
61 0 : nsRepeatService::GetInstance()->Stop(Notify, this);
62 0 : }
63 : void Notify();
64 0 : static void Notify(void* aData) {
65 0 : static_cast<nsAutoRepeatBoxFrame*>(aData)->Notify();
66 0 : }
67 :
68 : bool mTrustedEvent;
69 :
70 : bool IsActivatedOnHover();
71 : };
72 :
73 : nsIFrame*
74 0 : NS_NewAutoRepeatBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
75 : {
76 0 : return new (aPresShell) nsAutoRepeatBoxFrame(aContext);
77 : }
78 :
79 0 : NS_IMPL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame)
80 :
81 : nsresult
82 0 : nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext,
83 : WidgetGUIEvent* aEvent,
84 : nsEventStatus* aEventStatus)
85 : {
86 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
87 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
88 0 : return NS_OK;
89 : }
90 :
91 0 : switch(aEvent->mMessage) {
92 : // repeat mode may be "hover" for repeating while the mouse is hovering
93 : // over the element, otherwise repetition is done while the element is
94 : // active (pressed).
95 : case eMouseEnterIntoWidget:
96 : case eMouseOver:
97 0 : if (IsActivatedOnHover()) {
98 0 : StartRepeat();
99 0 : mTrustedEvent = aEvent->IsTrusted();
100 : }
101 0 : break;
102 :
103 : case eMouseExitFromWidget:
104 : case eMouseOut:
105 : // always stop on mouse exit
106 0 : StopRepeat();
107 : // Not really necessary but do this to be safe
108 0 : mTrustedEvent = false;
109 0 : break;
110 :
111 : case eMouseClick: {
112 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
113 0 : if (mouseEvent->IsLeftClickEvent()) {
114 : // skip button frame handling to prevent click handling
115 0 : return nsBoxFrame::HandleEvent(aPresContext, mouseEvent, aEventStatus);
116 : }
117 0 : break;
118 : }
119 :
120 : default:
121 0 : break;
122 : }
123 :
124 0 : return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
125 : }
126 :
127 : NS_IMETHODIMP
128 0 : nsAutoRepeatBoxFrame::HandlePress(nsPresContext* aPresContext,
129 : WidgetGUIEvent* aEvent,
130 : nsEventStatus* aEventStatus)
131 : {
132 0 : if (!IsActivatedOnHover()) {
133 0 : StartRepeat();
134 0 : mTrustedEvent = aEvent->IsTrusted();
135 0 : DoMouseClick(aEvent, mTrustedEvent);
136 : }
137 :
138 0 : return NS_OK;
139 : }
140 :
141 : NS_IMETHODIMP
142 0 : nsAutoRepeatBoxFrame::HandleRelease(nsPresContext* aPresContext,
143 : WidgetGUIEvent* aEvent,
144 : nsEventStatus* aEventStatus)
145 : {
146 0 : if (!IsActivatedOnHover()) {
147 0 : StopRepeat();
148 : }
149 0 : return NS_OK;
150 : }
151 :
152 : nsresult
153 0 : nsAutoRepeatBoxFrame::AttributeChanged(int32_t aNameSpaceID,
154 : nsIAtom* aAttribute,
155 : int32_t aModType)
156 : {
157 0 : if (aAttribute == nsGkAtoms::type) {
158 0 : StopRepeat();
159 : }
160 0 : return NS_OK;
161 : }
162 :
163 : void
164 0 : nsAutoRepeatBoxFrame::Notify()
165 : {
166 0 : DoMouseClick(nullptr, mTrustedEvent);
167 0 : }
168 :
169 : void
170 0 : nsAutoRepeatBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
171 : {
172 : // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
173 : // from under you while you're in the process of scrolling.
174 0 : StopRepeat();
175 0 : nsButtonBoxFrame::DestroyFrom(aDestructRoot);
176 0 : }
177 :
178 : bool
179 0 : nsAutoRepeatBoxFrame::IsActivatedOnHover()
180 : {
181 0 : return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::repeat,
182 0 : nsGkAtoms::hover, eCaseMatters);
183 : }
|