Flutter Linux Embedder
fl_pointer_manager.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 
6 
8 
9 static constexpr int kMicrosecondsPerMillisecond = 1000;
10 
12  GObject parent_instance;
13 
14  // Engine to send pointer events to.
15  GWeakRef engine;
16 
17  // ID to mark events with.
18  FlutterViewId view_id;
19 
20  // TRUE if the mouse pointer is inside the view, used for generating missing
21  // add events.
22  gboolean pointer_inside;
23 
24  // Pointer button state recorded for sending status updates.
25  int64_t button_state;
26 };
27 
28 G_DEFINE_TYPE(FlPointerManager, fl_pointer_manager, G_TYPE_OBJECT);
29 
30 // 8 corresponds to mouse back button on both x11 and wayland
31 static constexpr guint kMouseButtonBack = 8;
32 
33 // 9 corresponds to mouse forward button on both x11 and wayland
34 static constexpr guint kMouseButtonForward = 9;
35 
36 // Convert a GDK button ID into a Flutter button ID
37 static gboolean get_mouse_button(guint gdk_button, int64_t* button) {
38  switch (gdk_button) {
39  case GDK_BUTTON_PRIMARY:
40  *button = kFlutterPointerButtonMousePrimary;
41  return TRUE;
42  case GDK_BUTTON_MIDDLE:
43  *button = kFlutterPointerButtonMouseMiddle;
44  return TRUE;
45  case GDK_BUTTON_SECONDARY:
46  *button = kFlutterPointerButtonMouseSecondary;
47  return TRUE;
48  case kMouseButtonBack:
49  *button = kFlutterPointerButtonMouseBack;
50  return TRUE;
52  *button = kFlutterPointerButtonMouseForward;
53  return TRUE;
54  default:
55  return FALSE;
56  }
57 }
58 
59 static gboolean get_button(FlutterPointerDeviceKind device_kind,
60  guint gdk_button,
61  int64_t* button) {
62  if (device_kind == kFlutterPointerDeviceKindStylus ||
63  device_kind == kFlutterPointerDeviceKindInvertedStylus) {
64  // GDK button names describe the physical button action, where "primary"
65  // is the stylus tip contact. Flutter stylus button names reserve "primary"
66  // for the first barrel button, so the GDK secondary button maps there.
67  switch (gdk_button) {
68  case GDK_BUTTON_PRIMARY:
69  *button = kFlutterPointerButtonStylusContact;
70  return TRUE;
71  case GDK_BUTTON_SECONDARY:
72  *button = kFlutterPointerButtonStylusPrimary;
73  return TRUE;
74  case GDK_BUTTON_MIDDLE:
75  *button = kFlutterPointerButtonStylusSecondary;
76  return TRUE;
77  default:
78  return FALSE;
79  }
80  }
81 
82  return get_mouse_button(gdk_button, button);
83 }
84 
85 // Generates a mouse pointer event if the pointer appears inside the window.
86 static void ensure_pointer_added(FlPointerManager* self,
87  guint event_time,
88  FlutterPointerDeviceKind device_kind,
89  gdouble x,
90  gdouble y,
91  gdouble rotation,
92  gdouble pressure) {
93  if (self->pointer_inside) {
94  return;
95  }
96  self->pointer_inside = TRUE;
97 
98  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
99  if (engine == nullptr) {
100  return;
101  }
102 
104  engine, self->view_id, kAdd, event_time * kMicrosecondsPerMillisecond, x,
105  y, device_kind, 0, 0, self->button_state, rotation, pressure);
106 }
107 
108 static void fl_pointer_manager_dispose(GObject* object) {
109  FlPointerManager* self = FL_POINTER_MANAGER(object);
110 
111  g_weak_ref_clear(&self->engine);
112 
113  G_OBJECT_CLASS(fl_pointer_manager_parent_class)->dispose(object);
114 }
115 
116 static void fl_pointer_manager_class_init(FlPointerManagerClass* klass) {
117  G_OBJECT_CLASS(klass)->dispose = fl_pointer_manager_dispose;
118 }
119 
120 static void fl_pointer_manager_init(FlPointerManager* self) {}
121 
122 FlPointerManager* fl_pointer_manager_new(FlutterViewId view_id,
123  FlEngine* engine) {
124  FlPointerManager* self =
125  FL_POINTER_MANAGER(g_object_new(fl_pointer_manager_get_type(), nullptr));
126 
127  self->view_id = view_id;
128  g_weak_ref_init(&self->engine, engine);
129 
130  return self;
131 }
132 
134  FlPointerManager* self,
135  guint event_time,
136  FlutterPointerDeviceKind device_kind,
137  gdouble x,
138  gdouble y,
139  guint gdk_button,
140  gdouble rotation,
141  gdouble pressure) {
142  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
143 
144  int64_t button;
145  if (!get_button(device_kind, gdk_button, &button)) {
146  return FALSE;
147  }
148 
149  ensure_pointer_added(self, event_time, device_kind, x, y, rotation, pressure);
150 
151  // Drop the event if Flutter already thinks the button is down.
152  if ((self->button_state & button) != 0) {
153  return FALSE;
154  }
155 
156  int old_button_state = self->button_state;
157  FlutterPointerPhase phase = kMove;
158  self->button_state ^= button;
159  phase = old_button_state == 0 ? kDown : kMove;
160 
161  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
162  if (engine == nullptr) {
163  return FALSE;
164  }
165 
167  engine, self->view_id, phase, event_time * kMicrosecondsPerMillisecond, x,
168  y, device_kind, 0, 0, self->button_state, rotation, pressure);
169 
170  return TRUE;
171 }
172 
174  FlPointerManager* self,
175  guint event_time,
176  FlutterPointerDeviceKind device_kind,
177  gdouble x,
178  gdouble y,
179  guint gdk_button,
180  gdouble rotation,
181  gdouble pressure) {
182  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
183 
184  int64_t button;
185  if (!get_button(device_kind, gdk_button, &button)) {
186  return FALSE;
187  }
188 
189  // Drop the event if Flutter already thinks the button is up.
190  if ((self->button_state & button) == 0) {
191  return FALSE;
192  }
193 
194  FlutterPointerPhase phase = kMove;
195  self->button_state ^= button;
196 
197  phase = self->button_state == 0 ? kUp : kMove;
198 
199  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
200  if (engine == nullptr) {
201  return FALSE;
202  }
203 
205  engine, self->view_id, phase, event_time * kMicrosecondsPerMillisecond, x,
206  y, device_kind, 0, 0, self->button_state, rotation, pressure);
207 
208  return TRUE;
209 }
210 
211 gboolean fl_pointer_manager_handle_motion(FlPointerManager* self,
212  guint event_time,
213  FlutterPointerDeviceKind device_kind,
214  gdouble x,
215  gdouble y,
216  gdouble rotation,
217  gdouble pressure) {
218  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
219 
220  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
221  if (engine == nullptr) {
222  return FALSE;
223  }
224 
225  ensure_pointer_added(self, event_time, device_kind, x, y, rotation, pressure);
226 
228  engine, self->view_id, self->button_state != 0 ? kMove : kHover,
229  event_time * kMicrosecondsPerMillisecond, x, y, device_kind, 0, 0,
230  self->button_state, rotation, pressure);
231 
232  return TRUE;
233 }
234 
235 gboolean fl_pointer_manager_handle_enter(FlPointerManager* self,
236  guint event_time,
237  FlutterPointerDeviceKind device_kind,
238  gdouble x,
239  gdouble y,
240  gdouble rotation,
241  gdouble pressure) {
242  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
243 
244  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
245  if (engine == nullptr) {
246  return FALSE;
247  }
248 
249  ensure_pointer_added(self, event_time, device_kind, x, y, rotation, pressure);
250 
251  return TRUE;
252 }
253 
254 gboolean fl_pointer_manager_handle_leave(FlPointerManager* self,
255  guint event_time,
256  FlutterPointerDeviceKind device_kind,
257  gdouble x,
258  gdouble y,
259  gdouble rotation,
260  gdouble pressure) {
261  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
262 
263  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
264  if (engine == nullptr) {
265  return FALSE;
266  }
267 
268  // Don't remove pointer while button is down; In case of dragging outside of
269  // window with mouse grab active Gtk will send another leave notify on
270  // release.
271  if (self->pointer_inside && self->button_state == 0) {
272  fl_engine_send_mouse_pointer_event(engine, self->view_id, kRemove,
273  event_time * kMicrosecondsPerMillisecond,
274  x, y, device_kind, 0, 0,
275  self->button_state, rotation, pressure);
276  self->pointer_inside = FALSE;
277  }
278 
279  return TRUE;
280 }
g_autoptr(FlEngine) engine
FlFramebuffer double x
FlFramebuffer double double y
return TRUE
void fl_engine_send_mouse_pointer_event(FlEngine *self, FlutterViewId view_id, FlutterPointerPhase phase, size_t timestamp, double x, double y, FlutterPointerDeviceKind device_kind, double scroll_delta_x, double scroll_delta_y, int64_t buttons, double rotation, double pressure)
Definition: fl_engine.cc:1195
static gboolean get_button(FlutterPointerDeviceKind device_kind, guint gdk_button, int64_t *button)
gboolean fl_pointer_manager_handle_enter(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, gdouble rotation, gdouble pressure)
FlPointerManager * fl_pointer_manager_new(FlutterViewId view_id, FlEngine *engine)
G_DEFINE_TYPE(FlPointerManager, fl_pointer_manager, G_TYPE_OBJECT)
static void ensure_pointer_added(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, gdouble rotation, gdouble pressure)
static gboolean get_mouse_button(guint gdk_button, int64_t *button)
static void fl_pointer_manager_dispose(GObject *object)
static constexpr int kMicrosecondsPerMillisecond
gboolean fl_pointer_manager_handle_button_press(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, guint gdk_button, gdouble rotation, gdouble pressure)
static constexpr guint kMouseButtonForward
static constexpr guint kMouseButtonBack
static void fl_pointer_manager_class_init(FlPointerManagerClass *klass)
static void fl_pointer_manager_init(FlPointerManager *self)
gboolean fl_pointer_manager_handle_motion(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, gdouble rotation, gdouble pressure)
gboolean fl_pointer_manager_handle_button_release(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, guint gdk_button, gdouble rotation, gdouble pressure)
gboolean fl_pointer_manager_handle_leave(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, gdouble rotation, gdouble pressure)
G_BEGIN_DECLS FlutterViewId view_id