diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7ace4f7de27c2..832c014b39bfb 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -44789,6 +44789,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_node_test.cc + ../.. ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_text_field_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_application.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_application_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc + ../../../flutter/LICENSE 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 + ORIGIN: ../../../flutter/shell/platform/linux/key_mapping.g.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/key_mapping.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/key_mapping_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_application.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h + ../../../flutter/LICENSE 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 FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field.cc FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field.h FILE: ../../../flutter/shell/platform/linux/fl_accessible_text_field_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_application.cc +FILE: ../../../flutter/shell/platform/linux/fl_application_test.cc FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc @@ -47833,6 +47838,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_window_state_monitor_test.cc FILE: ../../../flutter/shell/platform/linux/key_mapping.g.cc FILE: ../../../flutter/shell/platform/linux/key_mapping.h FILE: ../../../flutter/shell/platform/linux/key_mapping_test.cc +FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_application.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index ef05b4ddd2117..13511e93e4b32 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -43,6 +43,7 @@ if (build_glfw_shell) { } _public_headers = [ + "public/flutter_linux/fl_application.h", "public/flutter_linux/fl_basic_message_channel.h", "public/flutter_linux/fl_binary_codec.h", "public/flutter_linux/fl_binary_messenger.h", @@ -99,6 +100,7 @@ source_set("flutter_linux_sources") { sources = [ "fl_accessible_node.cc", "fl_accessible_text_field.cc", + "fl_application.cc", "fl_basic_message_channel.cc", "fl_binary_codec.cc", "fl_binary_messenger.cc", @@ -197,6 +199,7 @@ executable("flutter_linux_unittests") { sources = [ "fl_accessible_node_test.cc", "fl_accessible_text_field_test.cc", + "fl_application_test.cc", "fl_basic_message_channel_test.cc", "fl_binary_codec_test.cc", "fl_binary_messenger_test.cc", diff --git a/shell/platform/linux/fl_application.cc b/shell/platform/linux/fl_application.cc new file mode 100644 index 0000000000000..84fc87d765ddf --- /dev/null +++ b/shell/platform/linux/fl_application.cc @@ -0,0 +1,159 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" + +struct FlApplicationPrivate { + // Arguments to pass to Dart. + gchar** dart_entrypoint_arguments; +}; + +#define FL_APPLICATION_GET_PRIVATE(app) \ + ((FlApplicationPrivate*)fl_application_get_instance_private( \ + FL_APPLICATION(app))) + +enum { kSignalRegisterPlugins, kSignalCreateWindow, kSignalLastSignal }; + +static guint fl_application_signals[kSignalLastSignal]; + +G_DEFINE_TYPE_WITH_CODE(FlApplication, + fl_application, + GTK_TYPE_APPLICATION, + G_ADD_PRIVATE(FlApplication)) + +// Default implementation of FlApplication::register_plugins +static void fl_application_register_plugins(FlApplication* self, + FlPluginRegistry* registry) {} + +// Default implementation of FlApplication::create_window +static GtkWindow* fl_application_create_window(FlApplication* self, + FlView* view) { + GtkApplicationWindow* window = + GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(self))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(window)); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(GTK_WINDOW(window), GTK_WIDGET(header_bar)); + } + + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + return GTK_WINDOW(window); +} + +// Implements GApplication::activate. +static void fl_application_activate(GApplication* application) { + FlApplication* self = FL_APPLICATION(application); + FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, priv->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + + GtkWindow* window; + g_signal_emit(self, fl_application_signals[kSignalCreateWindow], 0, view, + &window); + gtk_widget_show(GTK_WIDGET(window)); + + g_signal_emit(self, fl_application_signals[kSignalRegisterPlugins], 0, + FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean fl_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + FlApplication* self = FL_APPLICATION(application); + FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self); + + // Strip out the first argument as it is the binary name. + priv->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + // This will only run on the primary instance or this instance with + // G_APPLICATION_NON_UNIQUE + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void fl_application_dispose(GObject* object) { + FlApplication* self = FL_APPLICATION(object); + FlApplicationPrivate* priv = FL_APPLICATION_GET_PRIVATE(self); + + g_clear_pointer(&priv->dart_entrypoint_arguments, g_strfreev); + + G_OBJECT_CLASS(fl_application_parent_class)->dispose(object); +} + +static void fl_application_class_init(FlApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = fl_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + fl_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = fl_application_dispose; + + klass->register_plugins = fl_application_register_plugins; + klass->create_window = fl_application_create_window; + + fl_application_signals[kSignalRegisterPlugins] = g_signal_new( + "register-plugins", fl_application_get_type(), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(FlApplicationClass, register_plugins), nullptr, nullptr, + nullptr, G_TYPE_NONE, 1, fl_plugin_registry_get_type()); + fl_application_signals[kSignalCreateWindow] = g_signal_new( + "create-window", fl_application_get_type(), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(FlApplicationClass, create_window), + g_signal_accumulator_first_wins, nullptr, nullptr, GTK_TYPE_WINDOW, 1, + fl_view_get_type()); +} + +static void fl_application_init(FlApplication* self) {} + +G_MODULE_EXPORT +FlApplication* fl_application_new(const gchar* application_id, + GApplicationFlags flags) { + return FL_APPLICATION(g_object_new(fl_application_get_type(), + "application-id", application_id, "flags", + flags, nullptr)); +} diff --git a/shell/platform/linux/fl_application_test.cc b/shell/platform/linux/fl_application_test.cc new file mode 100644 index 0000000000000..73b5dc1173f35 --- /dev/null +++ b/shell/platform/linux/fl_application_test.cc @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gtest/gtest.h" + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_application.h" + +TEST(FlApplicationTest, ConstructorArgs) { + g_autoptr(FlApplication) app = fl_application_new( + "com.example.TestApplication", G_APPLICATION_FLAGS_NONE); + + EXPECT_STREQ(g_application_get_application_id(G_APPLICATION(app)), + "com.example.TestApplication"); + EXPECT_EQ(g_application_get_flags(G_APPLICATION(app)), + G_APPLICATION_FLAGS_NONE); +} diff --git a/shell/platform/linux/public/flutter_linux/fl_application.h b/shell/platform/linux/public/flutter_linux/fl_application.h new file mode 100644 index 0000000000000..c4c4133bdf5a2 --- /dev/null +++ b/shell/platform/linux/public/flutter_linux/fl_application.h @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_ + +#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION) +#error "Only can be included directly." +#endif + +#include "fl_plugin_registry.h" +#include "fl_view.h" + +#include +#include + +G_BEGIN_DECLS + +G_MODULE_EXPORT +G_DECLARE_DERIVABLE_TYPE(FlApplication, + fl_application, + FL, + APPLICATION, + GtkApplication); + +/** + * FlApplicationClass: + * @register_plugins: invoked when plugins should be registered. + */ +struct _FlApplicationClass { + GtkApplicationClass parent_class; + + /** + * FlApplication::register_plugins: + * @application: the application + * @registry: registry to use. + * + * The ::register_plugins signal is emitted when plugins can be registered. + */ + void (*register_plugins)(FlApplication* application, + FlPluginRegistry* registry); + + /** + * FlApplication::create_window: + * @application: the application + * @view: the view to add to this window. + * + * The ::create_window signal is emitted when a needs to be created for a + * view. By handling this signal the application can create the appropriate + * window for the given view and set any window properties or additional + * widgets required. + * + * If this signal is not handled a standard GTK window will be created. + */ + GtkWindow* (*create_window)(FlApplication* application, FlView* view); +}; + +/** + * FlApplication: + * + * #Flutter-based application with the GTK embedder. + * + * Provides default behaviour for basic Flutter applications. + */ + +/** + * fl_application_new: + * @application_id: (allow-none): The application ID or %NULL. + * @flags: The application flags. + * + * Creates a new Flutter-based application. + * + * Returns: a new #FlApplication + */ +FlApplication* fl_application_new(const gchar* application_id, + GApplicationFlags flags); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_APPLICATION_H_ diff --git a/shell/platform/linux/public/flutter_linux/flutter_linux.h b/shell/platform/linux/public/flutter_linux/flutter_linux.h index 715cb5597bae2..c0d1483baa02f 100644 --- a/shell/platform/linux/public/flutter_linux/flutter_linux.h +++ b/shell/platform/linux/public/flutter_linux/flutter_linux.h @@ -7,6 +7,7 @@ #define __FLUTTER_LINUX_INSIDE__ +#include #include #include #include