OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // This file contains a function that receives a message from the message pump | |
6 // and dispatches that message to the appropriate root view. That function is | |
7 // 'DispatchEventForTouchUIGtk'. (Last function in this file.) | |
8 // | |
9 // The appropriate RootView is determined for each incoming event. The platform | |
10 // specific event is converted to a views event and dispatched directly to the | |
11 // appropriate RootView. | |
12 // | |
13 // This implementation is Gdk specific at the moment, but a future CL will | |
14 // provide a dispatcher that handles events from an X Windows message pump. | |
15 | |
16 // TODO(wyck): Make X Windows versions of all GdkEvent functions. | |
17 // (See individual TODO's below) | |
18 // | |
19 // When we switch the message pump from one that gives us GdkEvents to one that | |
20 // gives us X Windows events, we will need another version of each function. | |
21 // These ones are obviously specific to GdkEvent. | |
22 // | |
23 // Potential names: | |
24 // Maybe DispatchEventForTouchUIGtk will become DispatchEventForTouchUIX11. | |
25 // | |
26 // It may not be necessary to filter events with IsTouchEvent in the X version, | |
27 // because the message pump may pre-filter the message so that we get only | |
28 // touch events and there is nothing to filter out. | |
29 | |
30 #include <gdk/gdk.h> | |
31 #include <gdk/gdkx.h> | |
32 | |
33 #include "views/widget/root_view.h" | |
34 #include "views/widget/widget_gtk.h" | |
35 | |
36 namespace views { | |
37 | |
38 // gets the RootView associated with the GdkEvent. | |
39 // | |
40 // TODO(wyck): Make X Windows version of this function. (see earlier comment) | |
41 static RootView* FindRootViewForGdkEvent(GdkEvent* event) { | |
42 GdkEventAny* event_any = reinterpret_cast<GdkEventAny*>(event); | |
43 if (!event_any) { | |
44 DLOG(WARNING) << "FindRootViewForGdkEvent was passed a null GdkEvent"; | |
45 return NULL; | |
46 } | |
47 GdkWindow* gdk_window = event_any->window; | |
48 | |
49 // and get the parent | |
50 gpointer data = NULL; | |
51 gdk_window_get_user_data(gdk_window, &data); | |
52 GtkWidget* gtk_widget = reinterpret_cast<GtkWidget*>(data); | |
53 if (!gtk_widget) { | |
54 DLOG(WARNING) << "no GtkWidget found for that GdkWindow"; | |
55 return NULL; | |
56 } | |
57 WidgetGtk* widget_gtk = WidgetGtk::GetViewForNative(gtk_widget); | |
58 | |
59 if (!widget_gtk) { | |
60 DLOG(WARNING) << "no WidgetGtk found for that GtkWidget"; | |
61 return NULL; | |
62 } | |
63 return widget_gtk->GetRootView(); | |
64 } | |
65 | |
66 // Specialized dispatch for GDK_BUTTON_PRESS events | |
67 static void DispatchButtonPressGtk(const GdkEventButton& event, | |
68 RootView* root_view) { | |
69 // TODO(wyck): may need to remap coordinates: | |
70 // If so, it's like this: | |
71 // gdk_window_get_root_origin(dest, &dest_x, &dest_y); | |
72 // *x = event->x_root - dest_x; | |
73 // *y = event->y_root - dest_y; | |
74 | |
75 if (event.type == GDK_2BUTTON_PRESS || event.type == GDK_3BUTTON_PRESS) { | |
76 // TODO(wyck): decide what to do about 2 button and 3 button press msgs. | |
77 // You get both a GDK_BUTTON_PRESS and a GDK_2BUTTON_PRESS, so that's | |
78 // a bit weird. | |
79 // I'll ignore these events for now. | |
80 return; | |
81 } | |
82 | |
83 MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, event.x, event.y, | |
84 WidgetGtk::GetFlagsForEventButton(event)); | |
85 root_view->OnMousePressed(mouse_pressed); | |
86 } | |
87 | |
88 // Specialized dispatch for GDK_BUTTON_RELEASE events | |
89 static void DispatchButtonReleaseGtk(const GdkEventButton& event, | |
90 RootView* root_view) { | |
91 // TODO(wyck): may need to remap coordinates. | |
92 // If so, it's like this: | |
93 // gdk_window_get_root_origin(dest, &dest_x, &dest_y); | |
94 // *x = event->x_root - dest_x; | |
95 // *y = event->y_root - dest_y; | |
96 | |
97 MouseEvent mouse_up(Event::ET_MOUSE_RELEASED, event.x, event.y, | |
98 WidgetGtk::GetFlagsForEventButton(event)); | |
99 | |
100 root_view->OnMouseReleased(mouse_up, false); | |
101 } | |
102 | |
103 // Specialized dispatch for GDK_MOTION_NOTIFY events | |
104 static void DispatchMotionNotifyGtk(const GdkEventMotion& event, | |
105 RootView* root_view) { | |
106 // Regarding GDK_POINTER_MOTION_HINT_MASK: | |
107 // GDK_POINTER_MOTION_HINT_MASK may have been used to reduce the number of | |
108 // GDK_MOTION_NOTIFY events received. Normally a GDK_MOTION_NOTIFY event is | |
109 // received each time the mouse moves. But in the hint case, some events are | |
110 // marked with is_hint TRUE. Without further action after a hint, no more | |
111 // motion events will be received. | |
112 // To receive more motion events after a motion hint event, the application | |
113 // needs to ask for more by calling gdk_event_request_motions(). | |
114 if (event.is_hint) { | |
115 gdk_event_request_motions(&event); | |
116 } | |
117 | |
118 // TODO(wyck): handle dragging | |
119 // Apparently it's our job to determine the difference between a move and a | |
120 // drag. We should dispatch OnMouseDragged with ET_MOUSE_DRAGGED instead. | |
121 // It's unclear what constitutes the dragging state. Which button(s)? | |
122 int flags = Event::GetFlagsFromGdkState(event.state); | |
123 MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags); | |
124 root_view->OnMouseMoved(mouse_move); | |
125 } | |
126 | |
127 // Specialized dispatch for GDK_ENTER_NOTIFY events | |
128 static void DispatchEnterNotifyGtk(const GdkEventCrossing& event, | |
129 RootView* root_view) { | |
130 // TODO(wyck): I'm not sure if this is necessary yet | |
131 int flags = (Event::GetFlagsFromGdkState(event.state) & | |
132 ~(Event::EF_LEFT_BUTTON_DOWN | | |
133 Event::EF_MIDDLE_BUTTON_DOWN | | |
134 Event::EF_RIGHT_BUTTON_DOWN)); | |
135 MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags); | |
136 root_view->OnMouseMoved(mouse_move); | |
137 } | |
138 | |
139 // Specialized dispatch for GDK_LEAVE_NOTIFY events | |
140 static void DispatchLeaveNotifyGtk(const GdkEventCrossing& event, | |
141 RootView* root_view) { | |
142 // TODO(wyck): I'm not sure if this is necessary yet | |
143 root_view->ProcessOnMouseExited(); | |
144 } | |
145 | |
146 // Dispatch an input-related GdkEvent to a RootView | |
147 static void DispatchEventToRootViewGtk(GdkEvent* event, RootView* root_view) { | |
148 if (!event) { | |
149 DLOG(WARNING) << "DispatchEventToRootView was passed a null GdkEvent"; | |
150 return; | |
151 } | |
152 if (!root_view) { | |
153 DLOG(WARNING) << "DispatchEventToRootView was passed a null RootView"; | |
154 return; | |
155 } | |
156 switch (event->type) { | |
157 case GDK_BUTTON_PRESS: | |
158 DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event), | |
159 root_view); | |
160 break; | |
161 case GDK_BUTTON_RELEASE: | |
162 DispatchButtonReleaseGtk(*reinterpret_cast<GdkEventButton*>(event), | |
163 root_view); | |
164 break; | |
165 case GDK_MOTION_NOTIFY: | |
166 DispatchMotionNotifyGtk(*reinterpret_cast<GdkEventMotion*>(event), | |
167 root_view); | |
168 break; | |
169 case GDK_ENTER_NOTIFY: | |
170 DispatchEnterNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event), | |
171 root_view); | |
172 break; | |
173 case GDK_LEAVE_NOTIFY: | |
174 DispatchLeaveNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event), | |
175 root_view); | |
176 break; | |
177 case GDK_2BUTTON_PRESS: | |
178 DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event), | |
179 root_view); | |
180 break; | |
181 case GDK_3BUTTON_PRESS: | |
182 DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event), | |
183 root_view); | |
184 break; | |
185 default: | |
186 NOTREACHED(); | |
187 break; | |
188 } | |
189 } | |
190 | |
191 // Called for input-related events only. Dispatches them directly to the | |
192 // associated RootView. | |
193 // | |
194 // TODO(wyck): Make X Windows version of this function. (see earlier comment) | |
195 static void HijackEventForTouchUIGtk(GdkEvent* event) { | |
196 // TODO(wyck): something like this... | |
197 RootView* root_view = FindRootViewForGdkEvent(event); | |
198 if (!root_view) { | |
199 DLOG(WARNING) << "no RootView found for that GdkEvent"; | |
200 return; | |
201 } | |
202 DispatchEventToRootViewGtk(event, root_view); | |
203 } | |
204 | |
205 // returns true if the GdkEvent is a touch-related input event. | |
206 // | |
207 // TODO(wyck): Make X Windows version of this function. (see earlier comment) | |
208 // | |
209 // If the X Windows events are not-prefiltered, then we can provide a filtering | |
210 // function similar to this GdkEvent-specific function. Otherwise this function | |
211 // is not needed at all for the X Windows version. | |
212 static bool IsTouchEventGtk(GdkEvent* event) { | |
213 switch (event->type) { | |
214 case GDK_BUTTON_PRESS: | |
215 case GDK_BUTTON_RELEASE: | |
216 case GDK_MOTION_NOTIFY: | |
217 case GDK_ENTER_NOTIFY: | |
218 case GDK_LEAVE_NOTIFY: | |
219 case GDK_2BUTTON_PRESS: | |
220 case GDK_3BUTTON_PRESS: | |
221 return true; | |
222 default: | |
223 return false; | |
224 } | |
225 } | |
226 | |
227 // This is the public entry point for the touch event dispatcher. | |
228 // | |
229 // Hijacks input-related events and routes them directly to a widget_gtk. | |
230 // Returns false for non-input-related events, in which case the caller is still | |
231 // responsible for dispatching the event. | |
232 // | |
233 // TODO(wyck): Make X Windows version of this function. (see earlier comment) | |
234 bool DispatchEventForTouchUIGtk(GdkEvent* event) { | |
235 // is this is an input-related event... | |
236 if (IsTouchEventGtk(event)) { | |
237 HijackEventForTouchUIGtk(event); | |
238 return true; | |
239 } else { | |
240 return false; | |
241 } | |
242 } | |
243 } // namespace views | |
OLD | NEW |