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