OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 #include "views/focus/accelerator_handler.h" | |
6 | |
7 #include <bitset> | |
8 #include <gtk/gtk.h> | |
9 #include <X11/extensions/XInput2.h> | |
10 | |
11 #include "ui/base/touch/touch_factory.h" | |
12 #include "ui/views/ime/input_method.h" | |
13 #include "views/events/event.h" | |
14 #include "views/focus/focus_manager.h" | |
15 #include "views/view.h" | |
16 #include "views/widget/native_widget.h" | |
17 | |
18 namespace views { | |
19 | |
20 namespace { | |
21 | |
22 Widget* FindWidgetForGdkWindow(GdkWindow* gdk_window) { | |
23 gpointer data = NULL; | |
24 gdk_window_get_user_data(gdk_window, &data); | |
25 GtkWidget* gtk_widget = reinterpret_cast<GtkWidget*>(data); | |
26 if (!gtk_widget || !GTK_IS_WIDGET(gtk_widget)) { | |
27 DLOG(WARNING) << "no GtkWidget found for that GdkWindow"; | |
28 return NULL; | |
29 } | |
30 Widget* widget = Widget::GetWidgetForNativeView(gtk_widget); | |
31 | |
32 if (!widget) { | |
33 DLOG(WARNING) << "no NativeWidgetGtk found for that GtkWidget"; | |
34 return NULL; | |
35 } | |
36 return widget; | |
37 } | |
38 | |
39 } // namespace | |
40 | |
41 bool DispatchX2Event(Widget* widget, XEvent* xev) { | |
42 XGenericEventCookie* cookie = &xev->xcookie; | |
43 switch (cookie->evtype) { | |
44 case XI_KeyPress: | |
45 case XI_KeyRelease: { | |
46 // TODO(sad): We don't capture XInput2 events from keyboard yet. | |
47 break; | |
48 } | |
49 #if defined(USE_XI2_MT) | |
50 case XI_TouchBegin: | |
51 case XI_TouchEnd: | |
52 case XI_TouchUpdate: { | |
53 // Hide the cursor when a touch event comes in. | |
54 ui::TouchFactory::GetInstance()->SetCursorVisible(false, false); | |
55 | |
56 // If the TouchEvent is processed by |widget|, then return. | |
57 TouchEvent touch(xev); | |
58 if (widget->OnTouchEvent(touch) != ui::TOUCH_STATUS_UNKNOWN) | |
59 return true; | |
60 | |
61 // We do not want to generate a mouse event for an unprocessed touch | |
62 // event here. That is already done by the gesture manager in | |
63 // RootView::OnTouchEvent. | |
64 return false; | |
65 } | |
66 #endif | |
67 case XI_ButtonPress: | |
68 case XI_ButtonRelease: | |
69 case XI_Motion: { | |
70 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(cookie->data); | |
71 | |
72 // Scrolling the wheel generates press/release events with button id's 4 | |
73 // and 5. In case of a wheelscroll, we do not want to show the cursor. | |
74 if (xievent->detail == 4 || xievent->detail == 5) { | |
75 MouseWheelEvent wheelev(xev); | |
76 return widget->OnMouseEvent(wheelev); | |
77 } | |
78 | |
79 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | |
80 // Is the event coming from a touch device? | |
81 if (factory->IsTouchDevice(xievent->sourceid)) { | |
82 // Hide the cursor when a touch event comes in. | |
83 factory->SetCursorVisible(false, false); | |
84 | |
85 // With XInput 2.0, XI_ButtonPress and XI_ButtonRelease events are | |
86 // ignored, as XI_Motion events contain enough data to detect finger | |
87 // press and release. See more notes in TouchFactory::TouchParam. | |
88 if ((cookie->evtype == XI_ButtonPress || | |
89 cookie->evtype == XI_ButtonRelease) && | |
90 factory->IsRealTouchDevice(xievent->sourceid)) | |
91 return false; | |
92 | |
93 // If the TouchEvent is processed by |widget|, then return. Otherwise | |
94 // let it fall through so it can be used as a MouseEvent, if desired. | |
95 TouchEvent touch(xev); | |
96 if (widget->OnTouchEvent(touch) != ui::TOUCH_STATUS_UNKNOWN) | |
97 return true; | |
98 | |
99 // We do not want to generate a mouse event for an unprocessed touch | |
100 // event here. That is already done by the gesture manager in | |
101 // RootView::OnTouchEvent. | |
102 return false; | |
103 } else { | |
104 MouseEvent mouseev(xev); | |
105 | |
106 // Show the cursor. Start a timer to hide the cursor after a delay on | |
107 // move (not drag) events, or if the only button pressed is released. | |
108 bool start_timer = mouseev.type() == ui::ET_MOUSE_MOVED; | |
109 start_timer |= mouseev.type() == ui::ET_MOUSE_RELEASED && | |
110 (mouseev.IsOnlyLeftMouseButton() || | |
111 mouseev.IsOnlyMiddleMouseButton() || | |
112 mouseev.IsOnlyRightMouseButton()); | |
113 factory->SetCursorVisible(true, start_timer); | |
114 | |
115 return widget->OnMouseEvent(mouseev); | |
116 } | |
117 } | |
118 } | |
119 return false; | |
120 } | |
121 | |
122 bool DispatchXEvent(XEvent* xev) { | |
123 GdkDisplay* gdisp = gdk_display_get_default(); | |
124 XID xwindow = xev->xany.window; | |
125 | |
126 if (xev->type == GenericEvent) { | |
127 if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(xev)) | |
128 return true; // Consume the event. | |
129 | |
130 XGenericEventCookie* cookie = &xev->xcookie; | |
131 if (cookie->evtype == XI_HierarchyChanged) { | |
132 ui::TouchFactory::GetInstance()->UpdateDeviceList(cookie->display); | |
133 return true; | |
134 } | |
135 | |
136 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(cookie->data); | |
137 xwindow = xiev->event; | |
138 } | |
139 | |
140 GdkWindow* gwind = gdk_window_lookup_for_display(gdisp, xwindow); | |
141 Widget* widget = FindWidgetForGdkWindow(gwind); | |
142 if (widget) { | |
143 switch (xev->type) { | |
144 case KeyPress: | |
145 case KeyRelease: { | |
146 KeyEvent keyev(xev); | |
147 InputMethod* ime = widget->GetInputMethod(); | |
148 // Always dispatch key events to the input method first, to make sure | |
149 // that the input method's hotkeys work all time. | |
150 if (ime) { | |
151 ime->DispatchKeyEvent(keyev); | |
152 return true; | |
153 } | |
154 return widget->OnKeyEvent(keyev); | |
155 } | |
156 case ButtonPress: | |
157 case ButtonRelease: | |
158 if (xev->xbutton.button == 4 || xev->xbutton.button == 5) { | |
159 // Scrolling the wheel triggers button press/release events. | |
160 MouseWheelEvent wheelev(xev); | |
161 return widget->OnMouseEvent(wheelev); | |
162 } | |
163 // fallthrough | |
164 case MotionNotify: { | |
165 MouseEvent mouseev(xev); | |
166 return widget->OnMouseEvent(mouseev); | |
167 } | |
168 | |
169 case GenericEvent: { | |
170 return DispatchX2Event(widget, xev); | |
171 } | |
172 } | |
173 } | |
174 | |
175 return false; | |
176 } | |
177 | |
178 AcceleratorHandler::AcceleratorHandler() {} | |
179 | |
180 base::MessagePumpDispatcher::DispatchStatus | |
181 AcceleratorHandler::Dispatch(XEvent* xev) { | |
182 return DispatchXEvent(xev) ? | |
183 base::MessagePumpDispatcher::EVENT_PROCESSED : | |
184 base::MessagePumpDispatcher::EVENT_IGNORED; | |
185 } | |
186 | |
187 } // namespace views | |
OLD | NEW |