From 9b8c4bda6c9f245cd55e82809b6b9c3c0ecf3b8e Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Mon, 15 Jun 2020 11:51:34 +1200 Subject: [PATCH 1/4] Support headless mode --- plugins/color_panel/gtk/color_panel_plugin.cc | 8 ++- .../file_chooser/gtk/file_chooser_plugin.cc | 6 +++ plugins/menubar/gtk/menubar_plugin.cc | 12 ++++- plugins/window_size/gtk/window_size_plugin.cc | 33 +++++++++++++ testbed/gtk/CMakeLists.txt | 1 + testbed/gtk/fl_headless_application.cc | 49 +++++++++++++++++++ testbed/gtk/fl_headless_application.h | 19 +++++++ testbed/gtk/main.cc | 11 ++++- 8 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 testbed/gtk/fl_headless_application.cc create mode 100644 testbed/gtk/fl_headless_application.h diff --git a/plugins/color_panel/gtk/color_panel_plugin.cc b/plugins/color_panel/gtk/color_panel_plugin.cc index dd148d607..4f2b7a094 100644 --- a/plugins/color_panel/gtk/color_panel_plugin.cc +++ b/plugins/color_panel/gtk/color_panel_plugin.cc @@ -18,6 +18,7 @@ // See color_panel.dart for documentation. const char kChannelName[] = "flutter/colorpanel"; +const char kNoScreenError[] = "No Screen"; const char kShowColorPanelMethod[] = "ColorPanel.Show"; const char kColorPanelShowAlpha[] = "ColorPanel.ShowAlpha"; const char kHideColorPanelMethod[] = "ColorPanel.Hide"; @@ -92,9 +93,14 @@ static FlMethodResponse* show_color_panel(FlColorPanelPlugin* self, gboolean use_alpha = use_alpha_value != nullptr ? fl_value_get_bool(use_alpha_value) : FALSE; + FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + self->color_chooser_dialog = GTK_COLOR_CHOOSER_DIALOG( gtk_color_chooser_dialog_new(kWindowTitle, nullptr)); - FlView* view = fl_plugin_registrar_get_view(self->registrar); GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); gtk_window_set_transient_for(GTK_WINDOW(self->color_chooser_dialog), window); gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(self->color_chooser_dialog), diff --git a/plugins/file_chooser/gtk/file_chooser_plugin.cc b/plugins/file_chooser/gtk/file_chooser_plugin.cc index 4bad8269d..7c4fa948f 100644 --- a/plugins/file_chooser/gtk/file_chooser_plugin.cc +++ b/plugins/file_chooser/gtk/file_chooser_plugin.cc @@ -19,6 +19,7 @@ // See channel_controller.dart for documentation. const char kChannelName[] = "flutter/filechooser"; const char kBadArgumentsError[] = "Bad Arguments"; +const char kNoScreenError[] = "No Screen"; const char kShowOpenPanelMethod[] = "FileChooser.Show.Open"; const char kShowSavePanelMethod[] = "FileChooser.Show.Save"; const char kInitialDirectoryKey[] = "initialDirectory"; @@ -84,6 +85,11 @@ static FlMethodResponse* show_dialog(FlFileChooserPlugin* self, confirm_button_text = fl_value_get_string(value); FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); g_autoptr(GtkFileChooserNative) dialog = GTK_FILE_CHOOSER_NATIVE(gtk_file_chooser_native_new( diff --git a/plugins/menubar/gtk/menubar_plugin.cc b/plugins/menubar/gtk/menubar_plugin.cc index 74d9be7dc..0561cfafe 100644 --- a/plugins/menubar/gtk/menubar_plugin.cc +++ b/plugins/menubar/gtk/menubar_plugin.cc @@ -20,6 +20,7 @@ // See menu_channel.dart for documentation. const char kChannelName[] = "flutter/menubar"; const char kBadArgumentsError[] = "Bad Arguments"; +const char kNoScreenError[] = "No Screen"; const char kFailureError[] = "Failure"; const char kMenuSetMethod[] = "Menubar.SetMenu"; const char kMenuItemSelectedCallbackMethod[] = "Menubar.SelectedCallback"; @@ -145,6 +146,11 @@ static FlMethodResponse* menu_set(FlMenubarPlugin* self, FlValue* args) { } FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + GtkApplication* app = gtk_window_get_application( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); if (app == nullptr) { @@ -213,8 +219,10 @@ FlMenubarPlugin* fl_menubar_plugin_new(FlPluginRegistrar* registrar) { // Add a GAction for the menubar to trigger. FlView* view = fl_plugin_registrar_get_view(self->registrar); - GtkApplication* app = gtk_window_get_application( - GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); + GtkApplication* app = nullptr; + if (view != nullptr) + app = gtk_window_get_application( + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); if (app != nullptr) { g_autoptr(GSimpleAction) inactive_action = g_simple_action_new("flutter-menu-inactive", nullptr); diff --git a/plugins/window_size/gtk/window_size_plugin.cc b/plugins/window_size/gtk/window_size_plugin.cc index 27dc457d8..5409a0969 100644 --- a/plugins/window_size/gtk/window_size_plugin.cc +++ b/plugins/window_size/gtk/window_size_plugin.cc @@ -19,6 +19,7 @@ // See window_size_channel.dart for documentation. const char kChannelName[] = "flutter/windowsize"; const char kBadArgumentsError[] = "Bad Arguments"; +const char kNoScrenError[] = "No Screen"; const char kGetScreenListMethod[] = "getScreenList"; const char kGetWindowInfoMethod[] = "getWindowInfo"; const char kSetWindowFrameMethod[] = "setWindowFrame"; @@ -49,12 +50,16 @@ G_DEFINE_TYPE(FlWindowSizePlugin, fl_window_size_plugin, g_object_get_type()) // Gets the window being controlled. GtkWindow* get_window(FlWindowSizePlugin* self) { FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) return nullptr; + return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); } // Gets the display connection. GdkDisplay* get_display(FlWindowSizePlugin* self) { FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) return nullptr; + return gtk_widget_get_display(GTK_WIDGET(view)); } @@ -97,6 +102,11 @@ static FlMethodResponse* get_screen_list(FlWindowSizePlugin* self) { g_autoptr(FlValue) screens = fl_value_new_list(); GdkDisplay* display = get_display(self); + if (display == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + gint n_monitors = gdk_display_get_n_monitors(display); for (gint i = 0; i < n_monitors; i++) { GdkMonitor* monitor = gdk_display_get_monitor(display, i); @@ -109,6 +119,10 @@ static FlMethodResponse* get_screen_list(FlWindowSizePlugin* self) { // Gets information about the Flutter window. static FlMethodResponse* get_window_info(FlWindowSizePlugin* self) { GtkWindow* window = get_window(self); + if (window == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } g_autoptr(FlValue) window_info = fl_value_new_map(); @@ -158,6 +172,11 @@ static FlMethodResponse* set_window_frame(FlWindowSizePlugin* self, double height = fl_value_get_float(fl_value_get_list_value(args, 3)); GtkWindow* window = get_window(self); + if (window == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + gtk_window_move(window, static_cast(x), static_cast(y)); gtk_window_resize(window, static_cast(width), static_cast(height)); @@ -183,6 +202,11 @@ static FlMethodResponse* set_window_minimum_size(FlWindowSizePlugin* self, double width = fl_value_get_float(fl_value_get_list_value(args, 0)); double height = fl_value_get_float(fl_value_get_list_value(args, 1)); + if (get_window() == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + if (width >= 0 && height >= 0) { self->window_geometry.min_width = static_cast(width); self->window_geometry.min_height = static_cast(height); @@ -204,6 +228,11 @@ static FlMethodResponse* set_window_maximum_size(FlWindowSizePlugin* self, double width = fl_value_get_float(fl_value_get_list_value(args, 0)); double height = fl_value_get_float(fl_value_get_list_value(args, 1)); + if (get_window() == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } + self->window_geometry.max_width = static_cast(width); self->window_geometry.max_height = static_cast(height); @@ -221,6 +250,10 @@ static FlMethodResponse* set_window_title(FlWindowSizePlugin* self, } GtkWindow* window = get_window(self); + if (window == nullptr) { + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); + } gtk_window_set_title(window, fl_value_get_string(args)); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); diff --git a/testbed/gtk/CMakeLists.txt b/testbed/gtk/CMakeLists.txt index dfd5086ee..5a589688e 100644 --- a/testbed/gtk/CMakeLists.txt +++ b/testbed/gtk/CMakeLists.txt @@ -34,6 +34,7 @@ pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_executable(${BINARY_NAME} "main.cc" "fl_application.cc" + "fl_headless_application.cc" "window_configuration.cc" "${FLUTTER_MANAGED_DIR}/gtk_plugin_registrant.cc" ) diff --git a/testbed/gtk/fl_headless_application.cc b/testbed/gtk/fl_headless_application.cc new file mode 100644 index 000000000..782d2a64e --- /dev/null +++ b/testbed/gtk/fl_headless_application.cc @@ -0,0 +1,49 @@ +#include "fl_headless_application.h" + +#include +#include + +#include "flutter/gtk_plugin_registrant.h" + +struct _FlHeadlessApplication { + GApplication parent_instance; + + FlEngine* engine; +}; + +G_DEFINE_TYPE(FlHeadlessApplication, fl_headless_application, + G_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void fl_headless_application_activate(GApplication* application) { + FlHeadlessApplication* self = FL_HEADLESS_APPLICATION(application); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + self->engine = fl_engine_new_headless(project); + + g_application_hold(application); + + fl_register_plugins(FL_PLUGIN_REGISTRY(self->engine)); +} + +// Implements GObject::dispose. +static void fl_headless_application_dispose(GObject* object) { + FlHeadlessApplication* self = FL_HEADLESS_APPLICATION(object); + + g_clear_object(&self->engine); + + G_OBJECT_CLASS(fl_headless_application_parent_class)->dispose(object); +} + +static void fl_headless_application_class_init( + FlHeadlessApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = fl_headless_application_activate; + G_OBJECT_CLASS(klass)->dispose = fl_headless_application_dispose; +} + +static void fl_headless_application_init(FlHeadlessApplication* self) {} + +FlHeadlessApplication* fl_headless_application_new() { + return FL_HEADLESS_APPLICATION( + g_object_new(fl_headless_application_get_type(), nullptr)); +} diff --git a/testbed/gtk/fl_headless_application.h b/testbed/gtk/fl_headless_application.h new file mode 100644 index 000000000..947363988 --- /dev/null +++ b/testbed/gtk/fl_headless_application.h @@ -0,0 +1,19 @@ +#ifndef FLUTTER_FL_HEADLESS_APPLICATION_H_ +#define FLUTTER_FL_HEADLESS_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(FlHeadlessApplication, fl_headless_application, FL, + HEADLESS_APPLICATION, GApplication) + +/** + * fl_headless_application_new: + * + * Creates a new Flutter headless application. + * + * Returns: a new #FlHeadlessApplication. + */ +FlHeadlessApplication* fl_headless_application_new(); + +#endif // FLUTTER_FL_HEADLESS_APPLICATION_H_ + diff --git a/testbed/gtk/main.cc b/testbed/gtk/main.cc index 3a4ab89d0..5441c094d 100644 --- a/testbed/gtk/main.cc +++ b/testbed/gtk/main.cc @@ -1,6 +1,13 @@ #include "fl_application.h" +#include "fl_headless_application.h" int main(int argc, char** argv) { - g_autoptr(FlApplication) app = fl_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); + g_autoptr(GApplication) app = nullptr; + + if (gdk_init_check(&argc, &argv)) + app = G_APPLICATION(fl_application_new()); + else + app = G_APPLICATION(fl_headless_application_new()); + + return g_application_run(app, argc, argv); } From 73a89b46ed30e38e81bd03766eb56a97892c7ec2 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 16 Jun 2020 11:51:27 +1200 Subject: [PATCH 2/4] Typo --- plugins/window_size/gtk/window_size_plugin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/window_size/gtk/window_size_plugin.cc b/plugins/window_size/gtk/window_size_plugin.cc index 5409a0969..a2d2c6637 100644 --- a/plugins/window_size/gtk/window_size_plugin.cc +++ b/plugins/window_size/gtk/window_size_plugin.cc @@ -19,7 +19,7 @@ // See window_size_channel.dart for documentation. const char kChannelName[] = "flutter/windowsize"; const char kBadArgumentsError[] = "Bad Arguments"; -const char kNoScrenError[] = "No Screen"; +const char kNoScreenError[] = "No Screen"; const char kGetScreenListMethod[] = "getScreenList"; const char kGetWindowInfoMethod[] = "getWindowInfo"; const char kSetWindowFrameMethod[] = "setWindowFrame"; From 736eff6af716aff87ab256bfb27a6958c1486cba Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 17 Jun 2020 07:05:18 +1200 Subject: [PATCH 3/4] Remove headless from the template - only custom apps will make use of this --- testbed/gtk/CMakeLists.txt | 1 - testbed/gtk/fl_headless_application.cc | 49 -------------------------- testbed/gtk/fl_headless_application.h | 19 ---------- testbed/gtk/main.cc | 11 ++---- 4 files changed, 2 insertions(+), 78 deletions(-) delete mode 100644 testbed/gtk/fl_headless_application.cc delete mode 100644 testbed/gtk/fl_headless_application.h diff --git a/testbed/gtk/CMakeLists.txt b/testbed/gtk/CMakeLists.txt index 5a589688e..dfd5086ee 100644 --- a/testbed/gtk/CMakeLists.txt +++ b/testbed/gtk/CMakeLists.txt @@ -34,7 +34,6 @@ pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_executable(${BINARY_NAME} "main.cc" "fl_application.cc" - "fl_headless_application.cc" "window_configuration.cc" "${FLUTTER_MANAGED_DIR}/gtk_plugin_registrant.cc" ) diff --git a/testbed/gtk/fl_headless_application.cc b/testbed/gtk/fl_headless_application.cc deleted file mode 100644 index 782d2a64e..000000000 --- a/testbed/gtk/fl_headless_application.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "fl_headless_application.h" - -#include -#include - -#include "flutter/gtk_plugin_registrant.h" - -struct _FlHeadlessApplication { - GApplication parent_instance; - - FlEngine* engine; -}; - -G_DEFINE_TYPE(FlHeadlessApplication, fl_headless_application, - G_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void fl_headless_application_activate(GApplication* application) { - FlHeadlessApplication* self = FL_HEADLESS_APPLICATION(application); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - self->engine = fl_engine_new_headless(project); - - g_application_hold(application); - - fl_register_plugins(FL_PLUGIN_REGISTRY(self->engine)); -} - -// Implements GObject::dispose. -static void fl_headless_application_dispose(GObject* object) { - FlHeadlessApplication* self = FL_HEADLESS_APPLICATION(object); - - g_clear_object(&self->engine); - - G_OBJECT_CLASS(fl_headless_application_parent_class)->dispose(object); -} - -static void fl_headless_application_class_init( - FlHeadlessApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = fl_headless_application_activate; - G_OBJECT_CLASS(klass)->dispose = fl_headless_application_dispose; -} - -static void fl_headless_application_init(FlHeadlessApplication* self) {} - -FlHeadlessApplication* fl_headless_application_new() { - return FL_HEADLESS_APPLICATION( - g_object_new(fl_headless_application_get_type(), nullptr)); -} diff --git a/testbed/gtk/fl_headless_application.h b/testbed/gtk/fl_headless_application.h deleted file mode 100644 index 947363988..000000000 --- a/testbed/gtk/fl_headless_application.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FLUTTER_FL_HEADLESS_APPLICATION_H_ -#define FLUTTER_FL_HEADLESS_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(FlHeadlessApplication, fl_headless_application, FL, - HEADLESS_APPLICATION, GApplication) - -/** - * fl_headless_application_new: - * - * Creates a new Flutter headless application. - * - * Returns: a new #FlHeadlessApplication. - */ -FlHeadlessApplication* fl_headless_application_new(); - -#endif // FLUTTER_FL_HEADLESS_APPLICATION_H_ - diff --git a/testbed/gtk/main.cc b/testbed/gtk/main.cc index 5441c094d..3a4ab89d0 100644 --- a/testbed/gtk/main.cc +++ b/testbed/gtk/main.cc @@ -1,13 +1,6 @@ #include "fl_application.h" -#include "fl_headless_application.h" int main(int argc, char** argv) { - g_autoptr(GApplication) app = nullptr; - - if (gdk_init_check(&argc, &argv)) - app = G_APPLICATION(fl_application_new()); - else - app = G_APPLICATION(fl_headless_application_new()); - - return g_application_run(app, argc, argv); + g_autoptr(FlApplication) app = fl_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); } From aaa3ea1e51b4f07018f808293a9a477fafc475db Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Jun 2020 12:10:45 -0700 Subject: [PATCH 4/4] Add missing braces --- plugins/menubar/gtk/menubar_plugin.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/menubar/gtk/menubar_plugin.cc b/plugins/menubar/gtk/menubar_plugin.cc index 0561cfafe..d1de8e59b 100644 --- a/plugins/menubar/gtk/menubar_plugin.cc +++ b/plugins/menubar/gtk/menubar_plugin.cc @@ -220,9 +220,10 @@ FlMenubarPlugin* fl_menubar_plugin_new(FlPluginRegistrar* registrar) { // Add a GAction for the menubar to trigger. FlView* view = fl_plugin_registrar_get_view(self->registrar); GtkApplication* app = nullptr; - if (view != nullptr) + if (view != nullptr) { app = gtk_window_get_application( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); + } if (app != nullptr) { g_autoptr(GSimpleAction) inactive_action = g_simple_action_new("flutter-menu-inactive", nullptr);