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 // Generates a mouse pointer event if the pointer appears inside the window.
60 static void ensure_pointer_added(FlPointerManager* self,
61  guint event_time,
62  FlutterPointerDeviceKind device_kind,
63  gdouble x,
64  gdouble y) {
65  if (self->pointer_inside) {
66  return;
67  }
68  self->pointer_inside = TRUE;
69 
70  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
71  if (engine == nullptr) {
72  return;
73  }
74 
76  engine, self->view_id, kAdd, event_time * kMicrosecondsPerMillisecond, x,
77  y, device_kind, 0, 0, self->button_state);
78 }
79 
80 static void fl_pointer_manager_dispose(GObject* object) {
81  FlPointerManager* self = FL_POINTER_MANAGER(object);
82 
83  g_weak_ref_clear(&self->engine);
84 
85  G_OBJECT_CLASS(fl_pointer_manager_parent_class)->dispose(object);
86 }
87 
88 static void fl_pointer_manager_class_init(FlPointerManagerClass* klass) {
89  G_OBJECT_CLASS(klass)->dispose = fl_pointer_manager_dispose;
90 }
91 
92 static void fl_pointer_manager_init(FlPointerManager* self) {}
93 
94 FlPointerManager* fl_pointer_manager_new(FlutterViewId view_id,
95  FlEngine* engine) {
96  FlPointerManager* self =
97  FL_POINTER_MANAGER(g_object_new(fl_pointer_manager_get_type(), nullptr));
98 
99  self->view_id = view_id;
100  g_weak_ref_init(&self->engine, engine);
101 
102  return self;
103 }
104 
106  FlPointerManager* self,
107  guint event_time,
108  FlutterPointerDeviceKind device_kind,
109  gdouble x,
110  gdouble y,
111  guint gdk_button) {
112  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
113 
114  int64_t button;
115  if (!get_mouse_button(gdk_button, &button)) {
116  return FALSE;
117  }
118 
119  ensure_pointer_added(self, event_time, device_kind, x, y);
120 
121  // Drop the event if Flutter already thinks the button is down.
122  if ((self->button_state & button) != 0) {
123  return FALSE;
124  }
125 
126  int old_button_state = self->button_state;
127  FlutterPointerPhase phase = kMove;
128  self->button_state ^= button;
129  phase = old_button_state == 0 ? kDown : kMove;
130 
131  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
132  if (engine == nullptr) {
133  return FALSE;
134  }
135 
137  engine, self->view_id, phase, event_time * kMicrosecondsPerMillisecond, x,
138  y, device_kind, 0, 0, self->button_state);
139 
140  return TRUE;
141 }
142 
144  FlPointerManager* self,
145  guint event_time,
146  FlutterPointerDeviceKind device_kind,
147  gdouble x,
148  gdouble y,
149  guint gdk_button) {
150  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
151 
152  int64_t button;
153  if (!get_mouse_button(gdk_button, &button)) {
154  return FALSE;
155  }
156 
157  // Drop the event if Flutter already thinks the button is up.
158  if ((self->button_state & button) == 0) {
159  return FALSE;
160  }
161 
162  FlutterPointerPhase phase = kMove;
163  self->button_state ^= button;
164 
165  phase = self->button_state == 0 ? kUp : kMove;
166 
167  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
168  if (engine == nullptr) {
169  return FALSE;
170  }
171 
173  engine, self->view_id, phase, event_time * kMicrosecondsPerMillisecond, x,
174  y, device_kind, 0, 0, self->button_state);
175 
176  return TRUE;
177 }
178 
179 gboolean fl_pointer_manager_handle_motion(FlPointerManager* self,
180  guint event_time,
181  FlutterPointerDeviceKind device_kind,
182  gdouble x,
183  gdouble y) {
184  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
185 
186  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
187  if (engine == nullptr) {
188  return FALSE;
189  }
190 
191  ensure_pointer_added(self, event_time, device_kind, x, y);
192 
194  engine, self->view_id, self->button_state != 0 ? kMove : kHover,
195  event_time * kMicrosecondsPerMillisecond, x, y, device_kind, 0, 0,
196  self->button_state);
197 
198  return TRUE;
199 }
200 
201 gboolean fl_pointer_manager_handle_enter(FlPointerManager* self,
202  guint event_time,
203  FlutterPointerDeviceKind device_kind,
204  gdouble x,
205  gdouble y) {
206  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
207 
208  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
209  if (engine == nullptr) {
210  return FALSE;
211  }
212 
213  ensure_pointer_added(self, event_time, device_kind, x, y);
214 
215  return TRUE;
216 }
217 
218 gboolean fl_pointer_manager_handle_leave(FlPointerManager* self,
219  guint event_time,
220  FlutterPointerDeviceKind device_kind,
221  gdouble x,
222  gdouble y) {
223  g_return_val_if_fail(FL_IS_POINTER_MANAGER(self), FALSE);
224 
225  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
226  if (engine == nullptr) {
227  return FALSE;
228  }
229 
230  // Don't remove pointer while button is down; In case of dragging outside of
231  // window with mouse grab active Gtk will send another leave notify on
232  // release.
233  if (self->pointer_inside && self->button_state == 0) {
234  fl_engine_send_mouse_pointer_event(engine, self->view_id, kRemove,
235  event_time * kMicrosecondsPerMillisecond,
236  x, y, device_kind, 0, 0,
237  self->button_state);
238  self->pointer_inside = FALSE;
239  }
240 
241  return TRUE;
242 }
ensure_pointer_added
static void ensure_pointer_added(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y)
Definition: fl_pointer_manager.cc:60
fl_pointer_manager_init
static void fl_pointer_manager_init(FlPointerManager *self)
Definition: fl_pointer_manager.cc:92
_FlPointerManager::pointer_inside
gboolean pointer_inside
Definition: fl_pointer_manager.cc:22
fl_pointer_manager_handle_button_press
gboolean fl_pointer_manager_handle_button_press(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, guint gdk_button)
Definition: fl_pointer_manager.cc:105
_FlPointerManager::parent_instance
GObject parent_instance
Definition: fl_pointer_manager.cc:12
fl_pointer_manager_dispose
static void fl_pointer_manager_dispose(GObject *object)
Definition: fl_pointer_manager.cc:80
_FlPointerManager::view_id
FlutterViewId view_id
Definition: fl_pointer_manager.cc:18
fl_pointer_manager.h
_FlPointerManager::button_state
int64_t button_state
Definition: fl_pointer_manager.cc:25
kMicrosecondsPerMillisecond
static constexpr int kMicrosecondsPerMillisecond
Definition: fl_pointer_manager.cc:9
get_mouse_button
static gboolean get_mouse_button(guint gdk_button, int64_t *button)
Definition: fl_pointer_manager.cc:37
fl_pointer_manager_handle_button_release
gboolean fl_pointer_manager_handle_button_release(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y, guint gdk_button)
Definition: fl_pointer_manager.cc:143
G_DEFINE_TYPE
G_DEFINE_TYPE(FlPointerManager, fl_pointer_manager, G_TYPE_OBJECT)
fl_engine_private.h
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
kMouseButtonForward
static constexpr guint kMouseButtonForward
Definition: fl_pointer_manager.cc:34
_FlPointerManager::engine
GWeakRef engine
Definition: fl_pointer_manager.cc:15
fl_pointer_manager_handle_motion
gboolean fl_pointer_manager_handle_motion(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y)
Definition: fl_pointer_manager.cc:179
fl_pointer_manager_handle_leave
gboolean fl_pointer_manager_handle_leave(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y)
Definition: fl_pointer_manager.cc:218
fl_pointer_manager_handle_enter
gboolean fl_pointer_manager_handle_enter(FlPointerManager *self, guint event_time, FlutterPointerDeviceKind device_kind, gdouble x, gdouble y)
Definition: fl_pointer_manager.cc:201
_FlPointerManager
Definition: fl_pointer_manager.cc:11
fl_pointer_manager_class_init
static void fl_pointer_manager_class_init(FlPointerManagerClass *klass)
Definition: fl_pointer_manager.cc:88
fl_engine_send_mouse_pointer_event
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)
Definition: fl_engine.cc:961
kMouseButtonBack
static constexpr guint kMouseButtonBack
Definition: fl_pointer_manager.cc:31
fl_pointer_manager_new
FlPointerManager * fl_pointer_manager_new(FlutterViewId view_id, FlEngine *engine)
Definition: fl_pointer_manager.cc:94