summaryrefslogtreecommitdiffstats
path: root/views/touchui/touch_event_dispatcher_gtk.cc
blob: fc4fcd2e91a2c9945cf34b3b937f0d000972c4ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains a function that receives a message from the message pump
// and dispatches that message to the appropriate root view.  That function is
// 'DispatchEventForTouchUIGtk'.  (Last function in this file.)
//
// The appropriate RootView is determined for each incoming event.  The platform
// specific event is converted to a views event and dispatched directly to the
// appropriate RootView.
//
// This implementation is Gdk specific at the moment, but a future CL will
// provide a dispatcher that handles events from an X Windows message pump.

// TODO(wyck): Make X Windows versions of all GdkEvent functions.
// (See individual TODO's below)
//
// When we switch the message pump from one that gives us GdkEvents to one that
// gives us X Windows events, we will need another version of each function.
// These ones are obviously specific to GdkEvent.
//
// Potential names:
//   Maybe DispatchEventForTouchUIGtk will become DispatchEventForTouchUIX11.
//
// It may not be necessary to filter events with IsTouchEvent in the X version,
// because the message pump may pre-filter the message so that we get only
// touch events and there is nothing to filter out.

#include <gdk/gdk.h>
#include <gdk/gdkx.h>

#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"

namespace views {

// gets the RootView associated with the GdkEvent.
//
// TODO(wyck): Make X Windows version of this function. (see earlier comment)
static RootView* FindRootViewForGdkEvent(GdkEvent* event) {
  GdkEventAny* event_any = reinterpret_cast<GdkEventAny*>(event);
  if (!event_any) {
    DLOG(WARNING) << "FindRootViewForGdkEvent was passed a null GdkEvent";
    return NULL;
  }
  GdkWindow* gdk_window = event_any->window;

  // and get the parent
  gpointer data = NULL;
  gdk_window_get_user_data(gdk_window, &data);
  GtkWidget* gtk_widget = reinterpret_cast<GtkWidget*>(data);
  if (!gtk_widget) {
    DLOG(WARNING) << "no GtkWidget found for that GdkWindow";
    return NULL;
  }
  WidgetGtk* widget_gtk = WidgetGtk::GetViewForNative(gtk_widget);

  if (!widget_gtk) {
    DLOG(WARNING) << "no WidgetGtk found for that GtkWidget";
    return NULL;
  }
  return widget_gtk->GetRootView();
}

// Specialized dispatch for GDK_BUTTON_PRESS events
static void DispatchButtonPressGtk(const GdkEventButton& event,
                                   RootView* root_view) {
  // TODO(wyck): may need to remap coordinates:
  // If so, it's like this:
  // gdk_window_get_root_origin(dest, &dest_x, &dest_y);
  // *x = event->x_root - dest_x;
  // *y = event->y_root - dest_y;

  if (event.type == GDK_2BUTTON_PRESS || event.type == GDK_3BUTTON_PRESS) {
    // TODO(wyck): decide what to do about 2 button and 3 button press msgs.
    // You get both a GDK_BUTTON_PRESS and a GDK_2BUTTON_PRESS, so that's
    // a bit weird.
    // I'll ignore these events for now.
    return;
  }

  MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, event.x, event.y,
      WidgetGtk::GetFlagsForEventButton(event));
  root_view->OnMousePressed(mouse_pressed);
}

// Specialized dispatch for GDK_BUTTON_RELEASE events
static void DispatchButtonReleaseGtk(const GdkEventButton& event,
                                     RootView* root_view) {
  // TODO(wyck): may need to remap coordinates.
  // If so, it's like this:
  // gdk_window_get_root_origin(dest, &dest_x, &dest_y);
  // *x = event->x_root - dest_x;
  // *y = event->y_root - dest_y;

  MouseEvent mouse_up(Event::ET_MOUSE_RELEASED, event.x, event.y,
      WidgetGtk::GetFlagsForEventButton(event));

  root_view->OnMouseReleased(mouse_up, false);
}

// Specialized dispatch for GDK_MOTION_NOTIFY events
static void DispatchMotionNotifyGtk(const GdkEventMotion& event,
                                    RootView* root_view) {
  // Regarding GDK_POINTER_MOTION_HINT_MASK:
  // GDK_POINTER_MOTION_HINT_MASK may have been used to reduce the number of
  // GDK_MOTION_NOTIFY events received. Normally a GDK_MOTION_NOTIFY event is
  // received each time the mouse moves.  But in the hint case, some events are
  // marked with is_hint TRUE.  Without further action after a hint, no more
  // motion events will be received.
  // To receive more motion events after a motion hint event, the application
  // needs to ask for more by calling gdk_event_request_motions().
  if (event.is_hint) {
    gdk_event_request_motions(&event);
  }

  // TODO(wyck): handle dragging
  // Apparently it's our job to determine the difference between a move and a
  // drag.  We should dispatch OnMouseDragged with ET_MOUSE_DRAGGED instead.
  // It's unclear what constitutes the dragging state.  Which button(s)?
  int flags = Event::GetFlagsFromGdkState(event.state);
  MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags);
  root_view->OnMouseMoved(mouse_move);
}

// Specialized dispatch for GDK_ENTER_NOTIFY events
static void DispatchEnterNotifyGtk(const GdkEventCrossing& event,
                                   RootView* root_view) {
  // TODO(wyck): I'm not sure if this is necessary yet
  int flags = (Event::GetFlagsFromGdkState(event.state) &
               ~(Event::EF_LEFT_BUTTON_DOWN |
                 Event::EF_MIDDLE_BUTTON_DOWN |
                 Event::EF_RIGHT_BUTTON_DOWN));
  MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags);
  root_view->OnMouseMoved(mouse_move);
}

// Specialized dispatch for GDK_LEAVE_NOTIFY events
static void DispatchLeaveNotifyGtk(const GdkEventCrossing& event,
                                   RootView* root_view) {
  // TODO(wyck): I'm not sure if this is necessary yet
  root_view->ProcessOnMouseExited();
}

// Dispatch an input-related GdkEvent to a RootView
static void DispatchEventToRootViewGtk(GdkEvent* event, RootView* root_view) {
  if (!event) {
    DLOG(WARNING) << "DispatchEventToRootView was passed a null GdkEvent";
    return;
  }
  if (!root_view) {
    DLOG(WARNING) << "DispatchEventToRootView was passed a null RootView";
    return;
  }
  switch (event->type) {
    case GDK_BUTTON_PRESS:
      DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
                             root_view);
      break;
    case GDK_BUTTON_RELEASE:
      DispatchButtonReleaseGtk(*reinterpret_cast<GdkEventButton*>(event),
                               root_view);
      break;
    case GDK_MOTION_NOTIFY:
      DispatchMotionNotifyGtk(*reinterpret_cast<GdkEventMotion*>(event),
                              root_view);
      break;
    case GDK_ENTER_NOTIFY:
      DispatchEnterNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event),
                             root_view);
      break;
    case GDK_LEAVE_NOTIFY:
      DispatchLeaveNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event),
                             root_view);
      break;
    case GDK_2BUTTON_PRESS:
      DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
                             root_view);
      break;
    case GDK_3BUTTON_PRESS:
      DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
                             root_view);
      break;
    default:
      NOTREACHED();
      break;
  }
}

// Called for input-related events only.  Dispatches them directly to the
// associated RootView.
//
// TODO(wyck): Make X Windows version of this function. (see earlier comment)
static void HijackEventForTouchUIGtk(GdkEvent* event) {
  // TODO(wyck): something like this...
  RootView* root_view = FindRootViewForGdkEvent(event);
  if (!root_view) {
    DLOG(WARNING) << "no RootView found for that GdkEvent";
    return;
  }
  DispatchEventToRootViewGtk(event, root_view);
}

// returns true if the GdkEvent is a touch-related input event.
//
// TODO(wyck): Make X Windows version of this function. (see earlier comment)
//
// If the X Windows events are not-prefiltered, then we can provide a filtering
// function similar to this GdkEvent-specific function.  Otherwise this function
// is not needed at all for the X Windows version.
static bool IsTouchEventGtk(GdkEvent* event) {
  switch (event->type) {
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
    case GDK_MOTION_NOTIFY:
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
      return true;
    default:
      return false;
  }
}

// This is the public entry point for the touch event dispatcher.
//
// Hijacks input-related events and routes them directly to a widget_gtk.
// Returns false for non-input-related events, in which case the caller is still
// responsible for dispatching the event.
//
// TODO(wyck): Make X Windows version of this function. (see earlier comment)
bool DispatchEventForTouchUIGtk(GdkEvent* event) {
  // is this is an input-related event...
  if (IsTouchEventGtk(event)) {
    HijackEventForTouchUIGtk(event);
    return true;
  } else {
    return false;
  }
}
}  // namespace views