Flutter Engine
 
Loading...
Searching...
No Matches
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
10typedef struct {
11 GWeakRef engine;
12
13 FlWindowingChannel* channel;
14
15 GHashTable* windows_by_view_id;
17
19
20static guint signals[LAST_SIGNAL];
21
22G_DEFINE_TYPE_WITH_PRIVATE(FlWindowingHandler,
23 fl_windowing_handler,
24 G_TYPE_OBJECT)
25
26typedef struct {
27 GtkWindow* window;
28 FlView* view;
29 guint first_frame_cb_id;
31
32static 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
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.
47static void first_frame_cb(FlView* view, WindowData* data) {
48 gtk_window_present(data->window);
49}
50
51static 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
69static FlMethodResponse* create_regular(FlWindowingSize* size,
70 FlWindowingSize* min_size,
71 FlWindowingSize* max_size,
72 const gchar* title,
73 FlWindowState state,
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
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
154static FlMethodResponse* modify_regular(int64_t view_id,
155 FlWindowingSize* size,
156 const gchar* title,
157 FlWindowState state,
158 gpointer user_data) {
159 FlWindowingHandler* self = FL_WINDOWING_HANDLER(user_data);
160
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)) {
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
200static 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
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
219static 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
232static 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
244static 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
260FlWindowingHandler* 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);
272
273 return self;
274}
GLFWwindow * window
Definition main.cc:60
FlutterEngine engine
Definition main.cc:84
FlView * view
g_signal_emit(self, fl_application_signals[SIGNAL_CREATE_WINDOW], 0, view, &window)
g_autoptr(GMutexLocker) locker
G_MODULE_EXPORT FlBinaryMessenger * fl_engine_get_binary_messenger(FlEngine *self)
G_MODULE_EXPORT FlMethodErrorResponse * fl_method_error_response_new(const gchar *code, const gchar *message, FlValue *details)
g_hash_table_insert(self->handlers, g_strdup(channel), handler_new(handler, user_data, destroy_notify))
const gchar FlBinaryMessengerMessageHandler handler
FlPixelBufferTexturePrivate * priv
G_MODULE_EXPORT FlView * fl_view_new_for_engine(FlEngine *engine)
Definition fl_view.cc:777
G_MODULE_EXPORT int64_t fl_view_get_id(FlView *self)
Definition fl_view.cc:796
G_BEGIN_DECLS FlutterViewId view_id
FlWindowingChannel * fl_windowing_channel_new(FlBinaryMessenger *messenger, FlWindowingChannelVTable *vtable, gpointer user_data)
FlMethodResponse * fl_windowing_channel_make_create_regular_response(int64_t view_id, FlWindowingSize *size, FlWindowState state)
FlMethodResponse * fl_windowing_channel_make_modify_regular_response()
FlMethodResponse * fl_windowing_channel_make_destroy_window_response()
@ FL_WINDOW_STATE_UNDEFINED
@ FL_WINDOW_STATE_MINIMIZED
@ FL_WINDOW_STATE_MAXIMIZED
@ FL_WINDOW_STATE_RESTORED
static void fl_windowing_handler_class_init(FlWindowingHandlerClass *klass)
static WindowData * get_window_data(FlWindowingHandler *self, int64_t view_id)
static guint signals[LAST_SIGNAL]
static FlMethodResponse * modify_regular(int64_t view_id, FlWindowingSize *size, const gchar *title, FlWindowState state, gpointer user_data)
static FlMethodResponse * create_regular(FlWindowingSize *size, FlWindowingSize *min_size, FlWindowingSize *max_size, const gchar *title, FlWindowState state, gpointer user_data)
FlWindowingHandler * fl_windowing_handler_new(FlEngine *engine)
static GtkWindow * fl_windowing_handler_create_window(FlWindowingHandler *handler, FlView *view)
static WindowData * window_data_new(GtkWindow *window, FlView *view)
static void window_data_free(WindowData *data)
static void fl_windowing_handler_dispose(GObject *object)
static void first_frame_cb(FlView *view, WindowData *data)
static FlMethodResponse * destroy_window(int64_t view_id, gpointer user_data)
@ SIGNAL_CREATE_WINDOW
static void fl_windowing_handler_init(FlWindowingHandler *self)
static FlWindowingChannelVTable windowing_channel_vtable
G_DEFINE_TYPE_WITH_PRIVATE(FlWindowingHandler, fl_windowing_handler, G_TYPE_OBJECT) typedef struct
void gtk_widget_destroy(GtkWidget *widget)
Definition mock_gtk.cc:264
gboolean gtk_window_is_maximized(GtkWindow *window)
Definition mock_gtk.cc:211
void gtk_widget_show(GtkWidget *widget)
Definition mock_gtk.cc:256
void gtk_window_resize(GtkWindow *window, gint width, gint height)
Definition mock_gtk.cc:196
void gtk_window_deiconify(GtkWindow *window)
Definition mock_gtk.cc:221
void gtk_window_maximize(GtkWindow *window)
Definition mock_gtk.cc:201
void gtk_window_unmaximize(GtkWindow *window)
Definition mock_gtk.cc:206
void gtk_window_iconify(GtkWindow *window)
Definition mock_gtk.cc:216
void gtk_window_set_default_size(GtkWindow *window, gint width, gint height)
Definition mock_gtk.cc:178
GtkWidget * gtk_window_new(GtkWindowType type)
Definition mock_gtk.cc:171
GdkWindow * gtk_widget_get_window(GtkWidget *widget)
Definition mock_gtk.cc:298
void gtk_window_set_geometry_hints(GtkWindow *window, GtkWidget *widget, GdkGeometry *geometry, GdkWindowHints geometry_mask)
Definition mock_gtk.cc:188
GdkWindowState gdk_window_get_state(GdkWindow *window)
Definition mock_gtk.cc:89
void gtk_window_set_title(GtkWindow *window, const gchar *title)
Definition mock_gtk.cc:183
void gtk_widget_realize(GtkWidget *widget)
Definition mock_gtk.cc:252
FlMethodResponse *(* create_regular)(FlWindowingSize *size, FlWindowingSize *min_size, FlWindowingSize *max_size, const gchar *title, FlWindowState state, gpointer user_data)
std::shared_ptr< const fml::Mapping > data