44#ifdef GDK_WINDOWING_X11
55#include < gdk/gdkx.h>
66#endif
7+ #ifdef GDK_WINDOWING_WAYLAND
8+ #include < gdk/gdkwayland.h>
9+ #endif
710
811#include " flutter/generated_plugin_registrant.h"
912
1013struct _MyApplication {
1114 GtkApplication parent_instance;
1215 char ** dart_entrypoint_arguments;
16+ FlMethodChannel* window_channel;
1317};
1418
1519G_DEFINE_TYPE (MyApplication, my_application, GTK_TYPE_APPLICATION )
1620
21+ static FlMethodResponse* set_native_title_bar (GtkWindow* window,
22+ FlValue* args) {
23+ if (args == nullptr || fl_value_get_type (args) != FL_VALUE_TYPE_BOOL ) {
24+ return FL_METHOD_RESPONSE (fl_method_error_response_new (
25+ " invalid-argument" , " Expected a boolean nativeTitleBar value." ,
26+ nullptr ));
27+ }
28+ GdkWindow* gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
29+ if (gdk_window == nullptr ) {
30+ return FL_METHOD_RESPONSE (fl_method_error_response_new (
31+ " window-not-realized" , " The GTK window has not been realized." ,
32+ nullptr ));
33+ }
34+ #ifdef GDK_WINDOWING_WAYLAND
35+ if (GDK_IS_WAYLAND_WINDOW (gdk_window)) {
36+ const gboolean native_title_bar = fl_value_get_bool (args);
37+ if (native_title_bar) {
38+ gdk_wayland_window_announce_ssd (gdk_window);
39+ } else {
40+ gdk_wayland_window_announce_csd (gdk_window);
41+ }
42+ }
43+ #endif
44+ return FL_METHOD_RESPONSE (fl_method_success_response_new (nullptr ));
45+ }
46+
47+ static void window_method_call_cb (FlMethodChannel* channel,
48+ FlMethodCall* method_call,
49+ gpointer user_data) {
50+ GtkWindow* window = GTK_WINDOW (user_data);
51+ g_autoptr (FlMethodResponse) response = nullptr ;
52+ if (g_strcmp0 (fl_method_call_get_name (method_call), " setNativeTitleBar" ) ==
53+ 0 ) {
54+ response = set_native_title_bar (window, fl_method_call_get_args (method_call));
55+ } else {
56+ response = FL_METHOD_RESPONSE (fl_method_not_implemented_response_new ());
57+ }
58+ g_autoptr (GError) error = nullptr ;
59+ if (!fl_method_call_respond (method_call, response, &error)) {
60+ g_warning (" Failed to send window method response: %s" , error->message );
61+ }
62+ }
63+
64+ static void create_window_channel (MyApplication* self,
65+ FlView* view,
66+ GtkWindow* window) {
67+ FlEngine* engine = fl_view_get_engine (view);
68+ FlBinaryMessenger* messenger = fl_engine_get_binary_messenger (engine);
69+ g_autoptr (FlStandardMethodCodec) codec = fl_standard_method_codec_new ();
70+ self->window_channel = fl_method_channel_new (
71+ messenger, " linwood.dev/butterfly/window" , FL_METHOD_CODEC (codec));
72+ fl_method_channel_set_method_call_handler (
73+ self->window_channel , window_method_call_cb, window, nullptr );
74+ }
75+
1776// Called when first Flutter frame received.
1877static void first_frame_cb (MyApplication* self, FlView *view)
1978{
@@ -33,16 +92,24 @@ static void my_application_activate(GApplication* application) {
3392 // in case the window manager does more exotic layout, e.g. tiling.
3493 // If running on Wayland assume the header bar will work (may need changing
3594 // if future cases occur).
36- gboolean use_header_bar = TRUE ;
95+ gboolean use_header_bar = FALSE ;
3796#ifdef GDK_WINDOWING_X11
38- GdkScreen* screen = gtk_window_get_screen (window);
97+ GdkScreen* screen = gtk_window_get_screen (GTK_WINDOW ( window) );
3998 if (GDK_IS_X11_SCREEN (screen)) {
4099 const gchar* wm_name = gdk_x11_screen_get_window_manager_name (screen);
41- if (g_strcmp0 (wm_name, " GNOME Shell" ) ! = 0 ) {
42- use_header_bar = FALSE ;
100+ if (g_strcmp0 (wm_name, " GNOME Shell" ) = = 0 ) {
101+ use_header_bar = TRUE ;
43102 }
44- }
103+ } else
45104#endif
105+ {
106+ const gchar* current_desktop = g_getenv (" XDG_CURRENT_DESKTOP" );
107+ if (current_desktop != nullptr ) {
108+ g_auto (GStrv) desktops = g_strsplit (current_desktop, " :" , -1 );
109+ use_header_bar = g_strv_contains (
110+ reinterpret_cast <const gchar* const *>(desktops), " GNOME" );
111+ }
112+ }
46113 if (use_header_bar) {
47114 GtkHeaderBar* header_bar = GTK_HEADER_BAR (gtk_header_bar_new ());
48115 gtk_widget_show (GTK_WIDGET (header_bar));
@@ -73,6 +140,7 @@ static void my_application_activate(GApplication* application) {
73140
74141 fl_register_plugins (FL_PLUGIN_REGISTRY (view));
75142
143+ create_window_channel (self, view, window);
76144 gtk_widget_grab_focus (GTK_WIDGET (view));
77145}
78146
@@ -116,6 +184,7 @@ static void my_application_shutdown(GApplication* application) {
116184// Implements GObject::dispose.
117185static void my_application_dispose (GObject* object) {
118186 MyApplication* self = MY_APPLICATION (object);
187+ g_clear_object (&self->window_channel );
119188 g_clear_pointer (&self->dart_entrypoint_arguments , g_strfreev);
120189 G_OBJECT_CLASS (my_application_parent_class)->dispose (object);
121190}
0 commit comments