Flutter Linux Embedder
fl_windowing_handler.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 
9 
10 typedef struct {
11  GWeakRef engine;
12 
13  FlWindowingChannel* channel;
14 
15  GHashTable* windows_by_view_id;
17 
19 
20 static guint signals[LAST_SIGNAL];
21 
22 G_DEFINE_TYPE_WITH_PRIVATE(FlWindowingHandler,
23  fl_windowing_handler,
24  G_TYPE_OBJECT)
25 
26 typedef struct {
27  GtkWindow* window;
28  FlView* view;
29  guint first_frame_cb_id;
31 
32 static WindowData* window_data_new(GtkWindow* window, FlView* view) {
33  WindowData* data = g_new0(WindowData, 1);
34  data->window = GTK_WINDOW(g_object_ref(window));
35  data->view = FL_VIEW(g_object_ref(view));
36  return data;
37 }
38 
39 static void window_data_free(WindowData* data) {
40  g_signal_handler_disconnect(data->view, data->first_frame_cb_id);
41  g_object_unref(data->window);
42  g_object_unref(data->view);
43  g_free(data);
44 }
45 
46 // Called when the first frame is received.
47 static void first_frame_cb(FlView* view, WindowData* data) {
48  gtk_window_present(data->window);
49 }
50 
51 static WindowData* get_window_data(FlWindowingHandler* self, int64_t view_id) {
53  reinterpret_cast<FlWindowingHandlerPrivate*>(
54  fl_windowing_handler_get_instance_private(self));
55 
56  return static_cast<WindowData*>(
57  g_hash_table_lookup(priv->windows_by_view_id, GINT_TO_POINTER(view_id)));
58 }
59 
61  FlWindowingHandler* handler,
62  FlView* view) {
63  GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
64  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
65 
66  return GTK_WINDOW(window);
67 }
68 
69 static FlMethodResponse* create_regular(FlWindowingSize* size,
70  FlWindowingSize* min_size,
71  FlWindowingSize* max_size,
72  const gchar* title,
74  gpointer user_data) {
75  FlWindowingHandler* self = FL_WINDOWING_HANDLER(user_data);
77  reinterpret_cast<FlWindowingHandlerPrivate*>(
78  fl_windowing_handler_get_instance_private(self));
79 
80  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&priv->engine));
81  if (engine == nullptr) {
82  return FL_METHOD_RESPONSE(
83  fl_method_error_response_new("Internal error", "No engine", nullptr));
84  }
85 
86  FlView* view = fl_view_new_for_engine(engine);
87  gtk_widget_show(GTK_WIDGET(view));
88 
89  GtkWindow* window;
91  if (window == nullptr) {
92  return FL_METHOD_RESPONSE(fl_method_error_response_new(
93  "Internal error", "Failed to create window", nullptr));
94  }
95 
96  gtk_window_set_default_size(GTK_WINDOW(window), size->width, size->height);
97  if (title != nullptr) {
98  gtk_window_set_title(GTK_WINDOW(window), title);
99  }
100  switch (state) {
102  gtk_window_maximize(GTK_WINDOW(window));
103  break;
105  gtk_window_iconify(GTK_WINDOW(window));
106  break;
109  break;
110  }
111 
112  GdkGeometry geometry;
113  GdkWindowHints geometry_mask = static_cast<GdkWindowHints>(0);
114  if (min_size != nullptr) {
115  geometry.min_width = min_size->width;
116  geometry.min_height = min_size->height;
117  geometry_mask =
118  static_cast<GdkWindowHints>(geometry_mask | GDK_HINT_MIN_SIZE);
119  }
120  if (max_size != nullptr) {
121  geometry.max_width = max_size->width;
122  geometry.max_height = max_size->height;
123  geometry_mask =
124  static_cast<GdkWindowHints>(geometry_mask | GDK_HINT_MAX_SIZE);
125  }
126  if (geometry_mask != 0) {
127  gtk_window_set_geometry_hints(GTK_WINDOW(window), nullptr, &geometry,
128  geometry_mask);
129  }
130 
131  WindowData* data = window_data_new(GTK_WINDOW(window), view);
132  data->first_frame_cb_id =
133  g_signal_connect(view, "first-frame", G_CALLBACK(first_frame_cb), data);
134 
135  // Make the resources for the view so rendering can start.
136  // We'll show the view when we have the first frame.
137  gtk_widget_realize(GTK_WIDGET(view));
138 
139  g_hash_table_insert(priv->windows_by_view_id,
140  GINT_TO_POINTER(fl_view_get_id(view)), data);
141 
142  // We don't know the current size and dimensions, so just reflect back what
143  // was requested.
144  FlWindowingSize* initial_size = size;
145  FlWindowState initial_state = state;
146  if (initial_state == FL_WINDOW_STATE_UNDEFINED) {
147  initial_state = FL_WINDOW_STATE_RESTORED;
148  }
149 
151  fl_view_get_id(view), initial_size, initial_state);
152 }
153 
154 static FlMethodResponse* modify_regular(int64_t view_id,
155  FlWindowingSize* size,
156  const gchar* title,
158  gpointer user_data) {
159  FlWindowingHandler* self = FL_WINDOWING_HANDLER(user_data);
160 
161  WindowData* data = get_window_data(self, view_id);
162  if (data == nullptr) {
163  return FL_METHOD_RESPONSE(fl_method_error_response_new(
164  "Bad Arguments", "No window with given view ID", nullptr));
165  }
166 
167  if (size != nullptr) {
168  gtk_window_resize(data->window, size->width, size->height);
169  }
170 
171  if (title != nullptr) {
172  gtk_window_set_title(data->window, title);
173  }
174 
175  GdkWindowState window_state;
176  switch (state) {
178  if (gtk_window_is_maximized(data->window)) {
179  gtk_window_unmaximize(data->window);
180  }
181  window_state =
182  gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(data->window)));
183  if (window_state & GDK_WINDOW_STATE_ICONIFIED) {
184  gtk_window_deiconify(data->window);
185  }
186  break;
188  gtk_window_maximize(data->window);
189  break;
191  gtk_window_iconify(data->window);
192  break;
194  break;
195  }
196 
198 }
199 
200 static FlMethodResponse* destroy_window(int64_t view_id, gpointer user_data) {
201  FlWindowingHandler* self = FL_WINDOWING_HANDLER(user_data);
203  reinterpret_cast<FlWindowingHandlerPrivate*>(
204  fl_windowing_handler_get_instance_private(self));
205 
206  WindowData* data = get_window_data(self, view_id);
207  if (data == nullptr) {
208  return FL_METHOD_RESPONSE(fl_method_error_response_new(
209  "Bad Arguments", "No window with given view ID", nullptr));
210  }
211 
212  gtk_widget_destroy(GTK_WIDGET(data->window));
213 
214  g_hash_table_remove(priv->windows_by_view_id, GINT_TO_POINTER(view_id));
215 
217 }
218 
219 static void fl_windowing_handler_dispose(GObject* object) {
220  FlWindowingHandler* self = FL_WINDOWING_HANDLER(object);
222  reinterpret_cast<FlWindowingHandlerPrivate*>(
223  fl_windowing_handler_get_instance_private(self));
224 
225  g_weak_ref_clear(&priv->engine);
226  g_clear_object(&priv->channel);
227  g_clear_pointer(&priv->windows_by_view_id, g_hash_table_unref);
228 
229  G_OBJECT_CLASS(fl_windowing_handler_parent_class)->dispose(object);
230 }
231 
232 static void fl_windowing_handler_class_init(FlWindowingHandlerClass* klass) {
233  G_OBJECT_CLASS(klass)->dispose = fl_windowing_handler_dispose;
234 
235  klass->create_window = fl_windowing_handler_create_window;
236 
237  signals[SIGNAL_CREATE_WINDOW] = g_signal_new(
238  "create-window", fl_windowing_handler_get_type(), G_SIGNAL_RUN_LAST,
239  G_STRUCT_OFFSET(FlWindowingHandlerClass, create_window),
240  g_signal_accumulator_first_wins, nullptr, nullptr, GTK_TYPE_WINDOW, 1,
241  fl_view_get_type());
242 }
243 
244 static void fl_windowing_handler_init(FlWindowingHandler* self) {
246  reinterpret_cast<FlWindowingHandlerPrivate*>(
247  fl_windowing_handler_get_instance_private(self));
248 
249  priv->windows_by_view_id =
250  g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
251  reinterpret_cast<GDestroyNotify>(window_data_free));
252 }
253 
256  .modify_regular = modify_regular,
257  .destroy_window = destroy_window,
258 };
259 
260 FlWindowingHandler* fl_windowing_handler_new(FlEngine* engine) {
261  g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr);
262 
263  FlWindowingHandler* self = FL_WINDOWING_HANDLER(
264  g_object_new(fl_windowing_handler_get_type(), nullptr));
266  reinterpret_cast<FlWindowingHandlerPrivate*>(
267  fl_windowing_handler_get_instance_private(self));
268 
269  g_weak_ref_init(&priv->engine, engine);
270  priv->channel = fl_windowing_channel_new(
272 
273  return self;
274 }
first_frame_cb
static void first_frame_cb(FlView *view, WindowData *data)
Definition: fl_windowing_handler.cc:47
FlWindowingHandlerPrivate::engine
GWeakRef engine
Definition: fl_windowing_handler.cc:11
fl_windowing_handler_create_window
static GtkWindow * fl_windowing_handler_create_window(FlWindowingHandler *handler, FlView *view)
Definition: fl_windowing_handler.cc:60
FL_WINDOW_STATE_RESTORED
@ FL_WINDOW_STATE_RESTORED
Definition: fl_windowing_channel.h:22
fl_method_error_response_new
G_MODULE_EXPORT FlMethodErrorResponse * fl_method_error_response_new(const gchar *code, const gchar *message, FlValue *details)
Definition: fl_method_response.cc:144
create_regular
static FlMethodResponse * create_regular(FlWindowingSize *size, FlWindowingSize *min_size, FlWindowingSize *max_size, const gchar *title, FlWindowState state, gpointer user_data)
Definition: fl_windowing_handler.cc:69
fl_view_get_id
G_MODULE_EXPORT int64_t fl_view_get_id(FlView *self)
Definition: fl_view.cc:795
LAST_SIGNAL
@ LAST_SIGNAL
Definition: fl_windowing_handler.cc:18
FlWindowingSize::height
double height
Definition: fl_windowing_channel.h:30
window
return window
Definition: fl_application.cc:41
priv
FlPixelBufferTexturePrivate * priv
Definition: fl_pixel_buffer_texture.cc:30
fl_view_new_for_engine
G_MODULE_EXPORT FlView * fl_view_new_for_engine(FlEngine *engine)
Definition: fl_view.cc:764
modify_regular
static FlMethodResponse * modify_regular(int64_t view_id, FlWindowingSize *size, const gchar *title, FlWindowState state, gpointer user_data)
Definition: fl_windowing_handler.cc:154
FlWindowingChannelVTable::create_regular
FlMethodResponse *(* create_regular)(FlWindowingSize *size, FlWindowingSize *min_size, FlWindowingSize *max_size, const gchar *title, FlWindowState state, gpointer user_data)
Definition: fl_windowing_channel.h:41
FlWindowingHandlerPrivate::channel
FlWindowingChannel * channel
Definition: fl_windowing_handler.cc:13
fl_windowing_channel_new
FlWindowingChannel * fl_windowing_channel_new(FlBinaryMessenger *messenger, FlWindowingChannelVTable *vtable, gpointer user_data)
Definition: fl_windowing_channel.cc:257
FL_WINDOW_STATE_UNDEFINED
@ FL_WINDOW_STATE_UNDEFINED
Definition: fl_windowing_channel.h:21
SIGNAL_CREATE_WINDOW
@ SIGNAL_CREATE_WINDOW
Definition: fl_windowing_handler.cc:18
fl_engine_get_binary_messenger
G_MODULE_EXPORT FlBinaryMessenger * fl_engine_get_binary_messenger(FlEngine *self)
Definition: fl_engine.cc:1246
FlWindowingHandlerPrivate
Definition: fl_windowing_handler.cc:10
state
AtkStateType state
Definition: fl_accessible_node.cc:10
windowing_channel_vtable
static FlWindowingChannelVTable windowing_channel_vtable
Definition: fl_windowing_handler.cc:254
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
FL_WINDOW_STATE_MINIMIZED
@ FL_WINDOW_STATE_MINIMIZED
Definition: fl_windowing_channel.h:24
window_data_free
static void window_data_free(WindowData *data)
Definition: fl_windowing_handler.cc:39
FlWindowingHandlerPrivate::windows_by_view_id
GHashTable * windows_by_view_id
Definition: fl_windowing_handler.cc:15
destroy_window
static FlMethodResponse * destroy_window(int64_t view_id, gpointer user_data)
Definition: fl_windowing_handler.cc:200
fl_windowing_channel_make_destroy_window_response
FlMethodResponse * fl_windowing_channel_make_destroy_window_response()
Definition: fl_windowing_channel.cc:294
fl_windowing_channel.h
FL_WINDOW_STATE_MAXIMIZED
@ FL_WINDOW_STATE_MAXIMIZED
Definition: fl_windowing_channel.h:23
get_window_data
static WindowData * get_window_data(FlWindowingHandler *self, int64_t view_id)
Definition: fl_windowing_handler.cc:51
FlWindowingSize
Definition: fl_windowing_channel.h:28
FlWindowState
FlWindowState
Definition: fl_windowing_channel.h:20
fl_windowing_handler_dispose
static void fl_windowing_handler_dispose(GObject *object)
Definition: fl_windowing_handler.cc:219
fl_view.h
FlWindowingChannelVTable
Definition: fl_windowing_channel.h:40
fl_windowing_handler_init
static void fl_windowing_handler_init(FlWindowingHandler *self)
Definition: fl_windowing_handler.cc:244
signals
static guint signals[LAST_SIGNAL]
Definition: fl_windowing_handler.cc:20
view
FlView * view
Definition: fl_application.cc:36
window_data_new
static WindowData * window_data_new(GtkWindow *window, FlView *view)
Definition: fl_windowing_handler.cc:32
fl_windowing_channel_make_create_regular_response
FlMethodResponse * fl_windowing_channel_make_create_regular_response(int64_t view_id, FlWindowingSize *size, FlWindowState state)
Definition: fl_windowing_channel.cc:275
G_DEFINE_TYPE_WITH_PRIVATE
G_DEFINE_TYPE_WITH_PRIVATE(FlWindowingHandler, fl_windowing_handler, G_TYPE_OBJECT) typedef struct
Definition: fl_windowing_handler.cc:22
fl_windowing_handler_class_init
static void fl_windowing_handler_class_init(FlWindowingHandlerClass *klass)
Definition: fl_windowing_handler.cc:232
FlWindowingSize::width
double width
Definition: fl_windowing_channel.h:29
fl_windowing_handler.h
WindowData
WindowData
Definition: fl_windowing_handler.cc:30
fl_windowing_channel_make_modify_regular_response
FlMethodResponse * fl_windowing_channel_make_modify_regular_response()
Definition: fl_windowing_channel.cc:290
fl_windowing_handler_new
FlWindowingHandler * fl_windowing_handler_new(FlEngine *engine)
Definition: fl_windowing_handler.cc:260
g_signal_emit
g_signal_emit(self, fl_application_signals[SIGNAL_CREATE_WINDOW], 0, view, &window)