mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
fix(engine/linux): adapt windowing and accessibility for GTK4
This commit is contained in:
parent
ec5a872f41
commit
2f067fd481
@ -6,7 +6,9 @@
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_accessibility_channel.h"
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include "flutter/shell/platform/linux/fl_view_private.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
GWeakRef engine;
|
||||
@ -22,6 +24,14 @@ static void send_announcement(int64_t view_id,
|
||||
FlTextDirection text_direction,
|
||||
FlAssertiveness assertiveness,
|
||||
gpointer user_data) {
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
(void)view_id;
|
||||
(void)message;
|
||||
(void)text_direction;
|
||||
(void)assertiveness;
|
||||
(void)user_data;
|
||||
return;
|
||||
#else
|
||||
FlAccessibilityHandler* self = FL_ACCESSIBILITY_HANDLER(user_data);
|
||||
FlAccessibilityHandlerPrivate* priv =
|
||||
reinterpret_cast<FlAccessibilityHandlerPrivate*>(
|
||||
@ -41,6 +51,7 @@ static void send_announcement(int64_t view_id,
|
||||
FlViewAccessible* accessible = fl_view_get_accessible(view);
|
||||
fl_view_accessible_send_announcement(
|
||||
accessible, message, assertiveness == FL_ASSERTIVENESS_ASSERTIVE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fl_accessibility_handler_dispose(GObject* object) {
|
||||
|
||||
@ -37,7 +37,8 @@ G_DEFINE_TYPE_WITH_CODE(FlApplication,
|
||||
// Called when the first frame is received.
|
||||
static void first_frame_cb(FlApplication* self, FlView* view) {
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GtkWidget* window = gtk_widget_get_root(GTK_WIDGET(view));
|
||||
GtkRoot* root = gtk_widget_get_root(GTK_WIDGET(view));
|
||||
GtkWidget* window = root != nullptr ? GTK_WIDGET(root) : nullptr;
|
||||
#else
|
||||
GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(view));
|
||||
#endif
|
||||
@ -80,7 +81,11 @@ static GtkWindow* fl_application_create_window(FlApplication* self,
|
||||
if (use_header_bar) {
|
||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
gtk_header_bar_set_show_title_buttons(header_bar, TRUE);
|
||||
#else
|
||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||
#endif
|
||||
gtk_window_set_titlebar(GTK_WINDOW(window), GTK_WIDGET(header_bar));
|
||||
}
|
||||
|
||||
|
||||
@ -30,13 +30,23 @@ static void notify_display_update(FlDisplayMonitor* self) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GListModel* monitors = gdk_display_get_monitors(self->display);
|
||||
guint n_monitors = g_list_model_get_n_items(monitors);
|
||||
#else
|
||||
int n_monitors = gdk_display_get_n_monitors(self->display);
|
||||
#endif
|
||||
g_autofree FlutterEngineDisplay* displays =
|
||||
g_new0(FlutterEngineDisplay, n_monitors);
|
||||
for (int i = 0; i < n_monitors; i++) {
|
||||
for (guint i = 0; i < n_monitors; i++) {
|
||||
FlutterEngineDisplay* display = &displays[i];
|
||||
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkMonitor* monitor =
|
||||
GDK_MONITOR(g_list_model_get_item(monitors, i));
|
||||
#else
|
||||
GdkMonitor* monitor = gdk_display_get_monitor(self->display, i);
|
||||
#endif
|
||||
FlutterEngineDisplayId display_id = GPOINTER_TO_INT(
|
||||
g_hash_table_lookup(self->display_ids_by_monitor, monitor));
|
||||
if (display_id == 0) {
|
||||
@ -56,6 +66,10 @@ static void notify_display_update(FlDisplayMonitor* self) {
|
||||
display->width = geometry.width;
|
||||
display->height = geometry.height;
|
||||
display->device_pixel_ratio = gdk_monitor_get_scale_factor(monitor);
|
||||
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
g_object_unref(monitor);
|
||||
#endif
|
||||
}
|
||||
|
||||
fl_engine_notify_display_update(engine, displays, n_monitors);
|
||||
|
||||
@ -34,6 +34,28 @@ struct _FlPlatformHandler {
|
||||
|
||||
G_DEFINE_TYPE(FlPlatformHandler, fl_platform_handler, G_TYPE_OBJECT)
|
||||
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
// Called when clipboard text received.
|
||||
static void clipboard_text_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
|
||||
g_autofree gchar* text =
|
||||
gdk_clipboard_read_text_finish(GDK_CLIPBOARD(object), result, nullptr);
|
||||
fl_platform_channel_respond_clipboard_get_data(method_call, text);
|
||||
}
|
||||
|
||||
// Called when clipboard text received during has_strings.
|
||||
static void clipboard_text_has_strings_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
|
||||
g_autofree gchar* text =
|
||||
gdk_clipboard_read_text_finish(GDK_CLIPBOARD(object), result, nullptr);
|
||||
fl_platform_channel_respond_clipboard_has_strings(
|
||||
method_call, text != nullptr && strlen(text) > 0);
|
||||
}
|
||||
#else
|
||||
// Called when clipboard text received.
|
||||
static void clipboard_text_cb(GtkClipboard* clipboard,
|
||||
const gchar* text,
|
||||
@ -50,14 +72,21 @@ static void clipboard_text_has_strings_cb(GtkClipboard* clipboard,
|
||||
fl_platform_channel_respond_clipboard_has_strings(
|
||||
method_call, text != nullptr && strlen(text) > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Called when Flutter wants to copy to the clipboard.
|
||||
static FlMethodResponse* clipboard_set_data(FlMethodCall* method_call,
|
||||
const gchar* text,
|
||||
gpointer user_data) {
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkClipboard* clipboard =
|
||||
gdk_display_get_clipboard(gdk_display_get_default());
|
||||
gdk_clipboard_set_text(clipboard, text);
|
||||
#else
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get_default(gdk_display_get_default());
|
||||
gtk_clipboard_set_text(clipboard, text, -1);
|
||||
#endif
|
||||
|
||||
return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
}
|
||||
@ -72,10 +101,17 @@ static FlMethodResponse* clipboard_get_data(FlMethodCall* method_call,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkClipboard* clipboard =
|
||||
gdk_display_get_clipboard(gdk_display_get_default());
|
||||
gdk_clipboard_read_text_async(clipboard, nullptr, clipboard_text_cb,
|
||||
g_object_ref(method_call));
|
||||
#else
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get_default(gdk_display_get_default());
|
||||
gtk_clipboard_request_text(clipboard, clipboard_text_cb,
|
||||
g_object_ref(method_call));
|
||||
#endif
|
||||
|
||||
// Will respond later.
|
||||
return nullptr;
|
||||
@ -85,10 +121,18 @@ static FlMethodResponse* clipboard_get_data(FlMethodCall* method_call,
|
||||
// be pasted, without actually accessing the clipboard content itself.
|
||||
static FlMethodResponse* clipboard_has_strings(FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkClipboard* clipboard =
|
||||
gdk_display_get_clipboard(gdk_display_get_default());
|
||||
gdk_clipboard_read_text_async(clipboard, nullptr,
|
||||
clipboard_text_has_strings_cb,
|
||||
g_object_ref(method_call));
|
||||
#else
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get_default(gdk_display_get_default());
|
||||
gtk_clipboard_request_text(clipboard, clipboard_text_has_strings_cb,
|
||||
g_object_ref(method_call));
|
||||
#endif
|
||||
|
||||
// Will respond later.
|
||||
return nullptr;
|
||||
|
||||
@ -4,18 +4,24 @@
|
||||
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include <atk/atk.h>
|
||||
#endif
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#else
|
||||
#include <gdk/gdkwayland.h>
|
||||
#endif
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include <gtk/gtk-a11y.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "flutter/common/constants.h"
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include "flutter/shell/platform/linux/fl_accessible_node.h"
|
||||
#endif
|
||||
#include "flutter/shell/platform/linux/fl_compositor_opengl.h"
|
||||
#include "flutter/shell/platform/linux/fl_compositor_software.h"
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
@ -25,9 +31,13 @@
|
||||
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_pointer_manager.h"
|
||||
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include "flutter/shell/platform/linux/fl_socket_accessible.h"
|
||||
#endif
|
||||
#include "flutter/shell/platform/linux/fl_touch_manager.h"
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include "flutter/shell/platform/linux/fl_view_accessible.h"
|
||||
#endif
|
||||
#include "flutter/shell/platform/linux/fl_view_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_window_state_monitor.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
|
||||
@ -78,8 +88,10 @@ struct _FlView {
|
||||
// Manages touch events.
|
||||
FlTouchManager* touch_manager;
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
// Accessible tree from Flutter, exposed as an AtkPlug.
|
||||
FlViewAccessible* view_accessible;
|
||||
#endif
|
||||
|
||||
// Signal subscripton for cursor changes.
|
||||
guint cursor_changed_cb_id;
|
||||
@ -160,8 +172,26 @@ static void init_touch(FlView* self) {
|
||||
}
|
||||
|
||||
static FlutterPointerDeviceKind get_device_kind(GdkEvent* event) {
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkDevice* device = gdk_event_get_device(event);
|
||||
#else
|
||||
GdkDevice* device = gdk_event_get_source_device(event);
|
||||
#endif
|
||||
GdkInputSource source = gdk_device_get_source(device);
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
switch (source) {
|
||||
case GDK_SOURCE_PEN:
|
||||
case GDK_SOURCE_TABLET_PAD:
|
||||
return kFlutterPointerDeviceKindStylus;
|
||||
case GDK_SOURCE_TOUCHSCREEN:
|
||||
return kFlutterPointerDeviceKindTouch;
|
||||
case GDK_SOURCE_TOUCHPAD:
|
||||
case GDK_SOURCE_TRACKPOINT:
|
||||
case GDK_SOURCE_KEYBOARD:
|
||||
case GDK_SOURCE_MOUSE:
|
||||
return kFlutterPointerDeviceKindMouse;
|
||||
}
|
||||
#else
|
||||
switch (source) {
|
||||
case GDK_SOURCE_PEN:
|
||||
case GDK_SOURCE_ERASER:
|
||||
@ -176,6 +206,8 @@ static FlutterPointerDeviceKind get_device_kind(GdkEvent* event) {
|
||||
case GDK_SOURCE_MOUSE:
|
||||
return kFlutterPointerDeviceKindMouse;
|
||||
}
|
||||
#endif
|
||||
return kFlutterPointerDeviceKindMouse;
|
||||
}
|
||||
|
||||
// Called when the mouse cursor changes.
|
||||
@ -187,8 +219,12 @@ static void cursor_changed_cb(FlView* self) {
|
||||
if (surface == nullptr) {
|
||||
return;
|
||||
}
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
g_autoptr(GdkCursor) cursor = gdk_cursor_new_from_name(cursor_name, nullptr);
|
||||
#else
|
||||
g_autoptr(GdkCursor) cursor = gdk_cursor_new_from_name(
|
||||
fl_gtk_surface_get_display(surface), cursor_name);
|
||||
#endif
|
||||
fl_gtk_surface_set_cursor(surface, cursor);
|
||||
}
|
||||
|
||||
@ -260,7 +296,12 @@ static void update_semantics_cb(FlView* self,
|
||||
return;
|
||||
}
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
fl_view_accessible_handle_update_semantics(self->view_accessible, update);
|
||||
#else
|
||||
(void)self;
|
||||
(void)update;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Invoked by the engine right before the engine is restarted.
|
||||
@ -307,8 +348,12 @@ static void fl_view_plugin_registry_iface_init(
|
||||
|
||||
static void sync_modifier_if_needed(FlView* self, GdkEvent* event) {
|
||||
guint event_time = gdk_event_get_time(event);
|
||||
#if FLUTTER_LINUX_GTK4
|
||||
GdkModifierType event_state = gdk_event_get_modifier_state(event);
|
||||
#else
|
||||
GdkModifierType event_state = static_cast<GdkModifierType>(0);
|
||||
gdk_event_get_state(event, &event_state);
|
||||
#endif
|
||||
fl_keyboard_manager_sync_modifier_if_needed(
|
||||
fl_engine_get_keyboard_manager(self->engine), event_state, event_time);
|
||||
}
|
||||
@ -840,7 +885,9 @@ static void fl_view_dispose(GObject* object) {
|
||||
g_clear_object(&self->zoom_gesture);
|
||||
g_clear_object(&self->rotate_gesture);
|
||||
#endif
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
g_clear_object(&self->view_accessible);
|
||||
#endif
|
||||
g_clear_object(&self->cancellable);
|
||||
|
||||
G_OBJECT_CLASS(fl_view_parent_class)->dispose(object);
|
||||
@ -848,7 +895,9 @@ static void fl_view_dispose(GObject* object) {
|
||||
|
||||
// Implements GtkWidget::realize.
|
||||
static void fl_view_realize(GtkWidget* widget) {
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
FlView* self = FL_VIEW(widget);
|
||||
#endif
|
||||
|
||||
GTK_WIDGET_CLASS(fl_view_parent_class)->realize(widget);
|
||||
|
||||
@ -936,16 +985,20 @@ static void fl_view_class_init(FlViewClass* klass) {
|
||||
g_signal_new("first-frame", fl_view_get_type(), G_SIGNAL_RUN_LAST, 0,
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
gtk_widget_class_set_accessible_type(GTK_WIDGET_CLASS(klass),
|
||||
fl_socket_accessible_get_type());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Engine related construction.
|
||||
static void setup_engine(FlView* self) {
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
self->view_accessible = fl_view_accessible_new(self->engine, self->view_id);
|
||||
fl_socket_accessible_embed(
|
||||
FL_SOCKET_ACCESSIBLE(gtk_widget_get_accessible(GTK_WIDGET(self))),
|
||||
atk_plug_get_id(ATK_PLUG(self->view_accessible)));
|
||||
#endif
|
||||
|
||||
self->pointer_manager = fl_pointer_manager_new(self->view_id, self->engine);
|
||||
|
||||
@ -1144,7 +1197,9 @@ G_MODULE_EXPORT void fl_view_set_background_color(FlView* self,
|
||||
self->background_color = gdk_rgba_copy(color);
|
||||
}
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
FlViewAccessible* fl_view_get_accessible(FlView* self) {
|
||||
g_return_val_if_fail(FL_IS_VIEW(self), nullptr);
|
||||
return self->view_accessible;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -5,11 +5,13 @@
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_VIEW_PRIVATE_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_VIEW_PRIVATE_H_
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_view_accessible.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
#include "flutter/shell/platform/linux/fl_view_accessible.h"
|
||||
|
||||
/**
|
||||
* fl_view_get_accessible:
|
||||
* @view: an #FlView.
|
||||
@ -19,6 +21,7 @@ G_BEGIN_DECLS
|
||||
* Returns: an #FlViewAccessible.
|
||||
*/
|
||||
FlViewAccessible* fl_view_get_accessible(FlView* view);
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ struct _FlWindowMonitor {
|
||||
|
||||
G_DEFINE_TYPE(FlWindowMonitor, fl_window_monitor, G_TYPE_OBJECT)
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
static gboolean configure_event_cb(FlWindowMonitor* self,
|
||||
GdkEventConfigure* event) {
|
||||
flutter::IsolateScope scope(self->isolate);
|
||||
@ -42,6 +43,7 @@ static gboolean window_state_event_cb(FlWindowMonitor* self,
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void is_active_notify_cb(FlWindowMonitor* self) {
|
||||
flutter::IsolateScope scope(self->isolate);
|
||||
@ -102,10 +104,12 @@ G_MODULE_EXPORT FlWindowMonitor* fl_window_monitor_new(
|
||||
self->on_title_notify = on_title_notify;
|
||||
self->on_close = on_close;
|
||||
self->on_destroy = on_destroy;
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
g_signal_connect_swapped(window, "configure-event",
|
||||
G_CALLBACK(configure_event_cb), self);
|
||||
g_signal_connect_swapped(window, "window-state-event",
|
||||
G_CALLBACK(window_state_event_cb), self);
|
||||
#endif
|
||||
g_signal_connect_swapped(window, "notify::is-active",
|
||||
G_CALLBACK(is_active_notify_cb), self);
|
||||
g_signal_connect_swapped(window, "notify::title", G_CALLBACK(title_notify_cb),
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h"
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
static constexpr const char* kFlutterLifecycleChannel = "flutter/lifecycle";
|
||||
|
||||
static constexpr const char* kAppLifecycleStateResumed =
|
||||
@ -16,6 +17,7 @@ static constexpr const char* kAppLifecycleStateInactive =
|
||||
"AppLifecycleState.inactive";
|
||||
static constexpr const char* kAppLifecycleStateHidden =
|
||||
"AppLifecycleState.hidden";
|
||||
#endif
|
||||
|
||||
struct _FlWindowStateMonitor {
|
||||
GObject parent_instance;
|
||||
@ -37,6 +39,7 @@ struct _FlWindowStateMonitor {
|
||||
|
||||
G_DEFINE_TYPE(FlWindowStateMonitor, fl_window_state_monitor, G_TYPE_OBJECT);
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
static void send_lifecycle_state(FlWindowStateMonitor* self,
|
||||
const gchar* lifecycle_state) {
|
||||
g_autoptr(FlValue) value = fl_value_new_string(lifecycle_state);
|
||||
@ -52,6 +55,7 @@ static void send_lifecycle_state(FlWindowStateMonitor* self,
|
||||
fl_binary_messenger_send_on_channel(self->messenger, kFlutterLifecycleChannel,
|
||||
message, nullptr, nullptr, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FLUTTER_LINUX_GTK4
|
||||
static gboolean is_hidden(GdkWindowState state) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user