Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 90ee378

Browse files
Make FlApplication class (#54637)
An app can now be: ```c #include <flutter_linux/flutter_linux.h> #include "flutter/generated_plugin_registrant.h" static void register_plugins_cb(FlApplication *app, FlPluginRegistry *registry) { fl_register_plugins(registry); } static GtkWindow *create_window_cb(FlApplication *app, FlView *view) { GtkApplicationWindow *window = GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(app))); gtk_window_set_title(GTK_WINDOW(window), "flutter_application_test"); gtk_window_set_default_size(GTK_WINDOW(window), 1280, 720); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); return GTK_WINDOW(window); } int main(int argc, char** argv) { g_autoptr(FlApplication) app = fl_application_new(APPLICATION_ID, G_APPLICATION_NON_UNIQUE); g_signal_connect(app, "register-plugins", G_CALLBACK(register_plugins_cb), nullptr); g_signal_connect(app, "create-window", G_CALLBACK(create_window_cb), nullptr); return g_application_run(G_APPLICATION(app), argc, argv); } ``` With this simplified, we can now build multi-window behaviour without having to modify the template much in the future. Fixes flutter/flutter#142920
1 parent 0306a9a commit 90ee378

File tree

6 files changed

+267
-0
lines changed

6 files changed

+267
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44789,6 +44789,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_node_test.cc + ../..
4478944789
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field.cc + ../../../flutter/LICENSE
4479044790
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field.h + ../../../flutter/LICENSE
4479144791
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field_test.cc + ../../../flutter/LICENSE
44792+
ORIGIN: ../../../flutter/shell/platform/linux/fl_application.cc + ../../../flutter/LICENSE
44793+
ORIGIN: ../../../flutter/shell/platform/linux/fl_application_test.cc + ../../../flutter/LICENSE
4479244794
ORIGIN: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc + ../../../flutter/LICENSE
4479344795
ORIGIN: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc + ../../../flutter/LICENSE
4479444796
ORIGIN: ../../../flutter/shell/platform/linux/fl_binary_codec.cc + ../../../flutter/LICENSE
@@ -44910,6 +44912,7 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_window_state_monitor_test.cc +
4491044912
ORIGIN: ../../../flutter/shell/platform/linux/key_mapping.g.cc + ../../../flutter/LICENSE
4491144913
ORIGIN: ../../../flutter/shell/platform/linux/key_mapping.h + ../../../flutter/LICENSE
4491244914
ORIGIN: ../../../flutter/shell/platform/linux/key_mapping_test.cc + ../../../flutter/LICENSE
44915+
ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_application.h + ../../../flutter/LICENSE
4491344916
ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h + ../../../flutter/LICENSE
4491444917
ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h + ../../../flutter/LICENSE
4491544918
ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h + ../../../flutter/LICENSE
@@ -47712,6 +47715,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_accessible_node_test.cc
4771247715
FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field.cc
4771347716
FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field.h
4771447717
FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field_test.cc
47718+
FILE: ../../../flutter/shell/platform/linux/fl_application.cc
47719+
FILE: ../../../flutter/shell/platform/linux/fl_application_test.cc
4771547720
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc
4771647721
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc
4771747722
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc
@@ -47833,6 +47838,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_window_state_monitor_test.cc
4783347838
FILE: ../../../flutter/shell/platform/linux/key_mapping.g.cc
4783447839
FILE: ../../../flutter/shell/platform/linux/key_mapping.h
4783547840
FILE: ../../../flutter/shell/platform/linux/key_mapping_test.cc
47841+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_application.h
4783647842
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
4783747843
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h
4783847844
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h

shell/platform/linux/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ if (build_glfw_shell) {
4343
}
4444

4545
_public_headers = [
46+
"public/flutter_linux/fl_application.h",
4647
"public/flutter_linux/fl_basic_message_channel.h",
4748
"public/flutter_linux/fl_binary_codec.h",
4849
"public/flutter_linux/fl_binary_messenger.h",
@@ -99,6 +100,7 @@ source_set("flutter_linux_sources") {
99100
sources = [
100101
"fl_accessible_node.cc",
101102
"fl_accessible_text_field.cc",
103+
"fl_application.cc",
102104
"fl_basic_message_channel.cc",
103105
"fl_binary_codec.cc",
104106
"fl_binary_messenger.cc",
@@ -197,6 +199,7 @@ executable("flutter_linux_unittests") {
197199
sources = [
198200
"fl_accessible_node_test.cc",
199201
"fl_accessible_text_field_test.cc",
202+
"fl_application_test.cc",
200203
"fl_basic_message_channel_test.cc",
201204
"fl_binary_codec_test.cc",
202205
"fl_binary_messenger_test.cc",
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
5+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_application.h"
6+
7+
#include <gtk/gtk.h>
8+
#ifdef GDK_WINDOWING_X11
9+
#include <gdk/gdkx.h>
10+
#endif
11+
12+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
13+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h"
14+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
15+
16+
struct FlApplicationPrivate {
17+
// Arguments to pass to Dart.
18+
gchar** dart_entrypoint_arguments;
19+
};
20+
21+
#define FL_APPLICATION_GET_PRIVATE(app) \
22+
((FlApplicationPrivate*)fl_application_get_instance_private( \
23+
FL_APPLICATION(app)))
24+
25+
enum { kSignalRegisterPlugins, kSignalCreateWindow, kSignalLastSignal };
26+
27+
static guint fl_application_signals[kSignalLastSignal];
28+
29+
G_DEFINE_TYPE_WITH_CODE(FlApplication,
30+
fl_application,
31+
GTK_TYPE_APPLICATION,
32+
G_ADD_PRIVATE(FlApplication))
33+
34+
// Default implementation of FlApplication::register_plugins
35+
static void fl_application_register_plugins(FlApplication* self,
36+
FlPluginRegistry* registry) {}
37+
38+
// Default implementation of FlApplication::create_window
39+
static GtkWindow* fl_application_create_window(FlApplication* self,
40+
FlView* view) {
41+
GtkApplicationWindow* window =
42+
GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(self)));
43+
44+
// Use a header bar when running in GNOME as this is the common style used
45+
// by applications and is the setup most users will be using (e.g. Ubuntu
46+
// desktop).
47+
// If running on X and not using GNOME then just use a traditional title bar
48+
// in case the window manager does more exotic layout, e.g. tiling.
49+
// If running on Wayland assume the header bar will work (may need changing
50+
// if future cases occur).
51+
gboolean use_header_bar = TRUE;
52+
#ifdef GDK_WINDOWING_X11
53+
GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(window));
54+
if (GDK_IS_X11_SCREEN(screen)) {
55+
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
56+
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
57+
use_header_bar = FALSE;
58+
}
59+
}
60+
#endif
61+
if (use_header_bar) {
62+
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
63+
gtk_widget_show(GTK_WIDGET(header_bar));
64+
gtk_header_bar_set_show_close_button(header_bar, TRUE);
65+
gtk_window_set_titlebar(GTK_WINDOW(window), GTK_WIDGET(header_bar));
66+
}
67+
68+
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
69+
70+
return GTK_WINDOW(window);
71+
}
72+
73+
// Implements GApplication::activate.
74+
static void fl_application_activate(GApplication* application) {
75+
FlApplication* self = FL_APPLICATION(application);
76+
FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self);
77+
78+
g_autoptr(FlDartProject) project = fl_dart_project_new();
79+
fl_dart_project_set_dart_entrypoint_arguments(
80+
project, priv->dart_entrypoint_arguments);
81+
82+
FlView* view = fl_view_new(project);
83+
gtk_widget_show(GTK_WIDGET(view));
84+
85+
GtkWindow* window;
86+
g_signal_emit(self, fl_application_signals[kSignalCreateWindow], 0, view,
87+
&window);
88+
gtk_widget_show(GTK_WIDGET(window));
89+
90+
g_signal_emit(self, fl_application_signals[kSignalRegisterPlugins], 0,
91+
FL_PLUGIN_REGISTRY(view));
92+
93+
gtk_widget_grab_focus(GTK_WIDGET(view));
94+
}
95+
96+
// Implements GApplication::local_command_line.
97+
static gboolean fl_application_local_command_line(GApplication* application,
98+
gchar*** arguments,
99+
int* exit_status) {
100+
FlApplication* self = FL_APPLICATION(application);
101+
FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self);
102+
103+
// Strip out the first argument as it is the binary name.
104+
priv->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
105+
106+
g_autoptr(GError) error = nullptr;
107+
if (!g_application_register(application, nullptr, &error)) {
108+
g_warning("Failed to register: %s", error->message);
109+
*exit_status = 1;
110+
return TRUE;
111+
}
112+
113+
// This will only run on the primary instance or this instance with
114+
// G_APPLICATION_NON_UNIQUE
115+
g_application_activate(application);
116+
*exit_status = 0;
117+
118+
return TRUE;
119+
}
120+
121+
// Implements GObject::dispose.
122+
static void fl_application_dispose(GObject* object) {
123+
FlApplication* self = FL_APPLICATION(object);
124+
FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self);
125+
126+
g_clear_pointer(&priv->dart_entrypoint_arguments, g_strfreev);
127+
128+
G_OBJECT_CLASS(fl_application_parent_class)->dispose(object);
129+
}
130+
131+
static void fl_application_class_init(FlApplicationClass* klass) {
132+
G_APPLICATION_CLASS(klass)->activate = fl_application_activate;
133+
G_APPLICATION_CLASS(klass)->local_command_line =
134+
fl_application_local_command_line;
135+
G_OBJECT_CLASS(klass)->dispose = fl_application_dispose;
136+
137+
klass->register_plugins = fl_application_register_plugins;
138+
klass->create_window = fl_application_create_window;
139+
140+
fl_application_signals[kSignalRegisterPlugins] = g_signal_new(
141+
"register-plugins", fl_application_get_type(), G_SIGNAL_RUN_LAST,
142+
G_STRUCT_OFFSET(FlApplicationClass, register_plugins), nullptr, nullptr,
143+
nullptr, G_TYPE_NONE, 1, fl_plugin_registry_get_type());
144+
fl_application_signals[kSignalCreateWindow] = g_signal_new(
145+
"create-window", fl_application_get_type(), G_SIGNAL_RUN_LAST,
146+
G_STRUCT_OFFSET(FlApplicationClass, create_window),
147+
g_signal_accumulator_first_wins, nullptr, nullptr, GTK_TYPE_WINDOW, 1,
148+
fl_view_get_type());
149+
}
150+
151+
static void fl_application_init(FlApplication* self) {}
152+
153+
G_MODULE_EXPORT
154+
FlApplication* fl_application_new(const gchar* application_id,
155+
GApplicationFlags flags) {
156+
return FL_APPLICATION(g_object_new(fl_application_get_type(),
157+
"application-id", application_id, "flags",
158+
flags, nullptr));
159+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
5+
#include "gtest/gtest.h"
6+
7+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_application.h"
8+
9+
TEST(FlApplicationTest, ConstructorArgs) {
10+
g_autoptr(FlApplication) app = fl_application_new(
11+
"com.example.TestApplication", G_APPLICATION_FLAGS_NONE);
12+
13+
EXPECT_STREQ(g_application_get_application_id(G_APPLICATION(app)),
14+
"com.example.TestApplication");
15+
EXPECT_EQ(g_application_get_flags(G_APPLICATION(app)),
16+
G_APPLICATION_FLAGS_NONE);
17+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
5+
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_
6+
#define FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_
7+
8+
#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
9+
#error "Only <flutter_linux/flutter_linux.h> can be included directly."
10+
#endif
11+
12+
#include "fl_plugin_registry.h"
13+
#include "fl_view.h"
14+
15+
#include <gmodule.h>
16+
#include <gtk/gtk.h>
17+
18+
G_BEGIN_DECLS
19+
20+
G_MODULE_EXPORT
21+
G_DECLARE_DERIVABLE_TYPE(FlApplication,
22+
fl_application,
23+
FL,
24+
APPLICATION,
25+
GtkApplication);
26+
27+
/**
28+
* FlApplicationClass:
29+
* @register_plugins: invoked when plugins should be registered.
30+
*/
31+
struct _FlApplicationClass {
32+
GtkApplicationClass parent_class;
33+
34+
/**
35+
* FlApplication::register_plugins:
36+
* @application: the application
37+
* @registry: registry to use.
38+
*
39+
* The ::register_plugins signal is emitted when plugins can be registered.
40+
*/
41+
void (*register_plugins)(FlApplication* application,
42+
FlPluginRegistry* registry);
43+
44+
/**
45+
* FlApplication::create_window:
46+
* @application: the application
47+
* @view: the view to add to this window.
48+
*
49+
* The ::create_window signal is emitted when a needs to be created for a
50+
* view. By handling this signal the application can create the appropriate
51+
* window for the given view and set any window properties or additional
52+
* widgets required.
53+
*
54+
* If this signal is not handled a standard GTK window will be created.
55+
*/
56+
GtkWindow* (*create_window)(FlApplication* application, FlView* view);
57+
};
58+
59+
/**
60+
* FlApplication:
61+
*
62+
* #Flutter-based application with the GTK embedder.
63+
*
64+
* Provides default behaviour for basic Flutter applications.
65+
*/
66+
67+
/**
68+
* fl_application_new:
69+
* @application_id: (allow-none): The application ID or %NULL.
70+
* @flags: The application flags.
71+
*
72+
* Creates a new Flutter-based application.
73+
*
74+
* Returns: a new #FlApplication
75+
*/
76+
FlApplication* fl_application_new(const gchar* application_id,
77+
GApplicationFlags flags);
78+
79+
G_END_DECLS
80+
81+
#endif // FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_

shell/platform/linux/public/flutter_linux/flutter_linux.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#define __FLUTTER_LINUX_INSIDE__
99

10+
#include <flutter_linux/fl_application.h>
1011
#include <flutter_linux/fl_basic_message_channel.h>
1112
#include <flutter_linux/fl_binary_codec.h>
1213
#include <flutter_linux/fl_binary_messenger.h>

0 commit comments

Comments
 (0)