Merge pull request #76829 from bruvzg/ac_kit_direct

Implement screen reader support using AccessKit library.
This commit is contained in:
Thaddeus Crews 2025-04-08 12:32:47 -05:00
commit e6a61b1ecc
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
305 changed files with 32447 additions and 300 deletions

View file

@ -11,6 +11,7 @@ common_linuxbsd = [
"joypad_linux.cpp",
"freedesktop_portal_desktop.cpp",
"freedesktop_screensaver.cpp",
"freedesktop_at_spi_monitor.cpp",
]
if env["use_sowrap"]:

View file

@ -466,6 +466,24 @@ def configure(env: "SConsEnvironment"):
env.Append(CPPDEFINES=["WAYLAND_ENABLED"])
env.Append(LIBS=["rt"]) # Needed by glibc, used by _allocate_shm_file
if env["accesskit"]:
if env["accesskit_sdk_path"] != "":
env.Prepend(CPPPATH=[env["accesskit_sdk_path"] + "/include"])
if env["arch"] == "arm64":
env.Append(LIBPATH=[env["accesskit_sdk_path"] + "/lib/linux/arm64/static/"])
elif env["arch"] == "arm32":
env.Append(LIBPATH=[env["accesskit_sdk_path"] + "/lib/linux/arm32/static/"])
elif env["arch"] == "rv64":
env.Append(LIBPATH=[env["accesskit_sdk_path"] + "/lib/linux/riscv64gc/static/"])
elif env["arch"] == "x86_64":
env.Append(LIBPATH=[env["accesskit_sdk_path"] + "/lib/linux/x86_64/static/"])
elif env["arch"] == "x86_32":
env.Append(LIBPATH=[env["accesskit_sdk_path"] + "/lib/linux/x86/static/"])
env.Append(LIBS=["accesskit"])
else:
env.Append(CPPDEFINES=["ACCESSKIT_DYNAMIC"])
env.Append(CPPDEFINES=["ACCESSKIT_ENABLED"])
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
if not env["use_volk"]:

View file

@ -72,6 +72,11 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
}
}
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->file_exists(template_path.get_base_dir().path_join("libaccesskit." + arch + ".so"))) {
da->copy(template_path.get_base_dir().path_join("libaccesskit." + arch + ".so"), p_path.get_base_dir().path_join("libaccesskit." + arch + ".so"), get_chmod_flags());
}
bool export_as_zip = p_path.ends_with("zip");
String pkg_name;

View file

@ -0,0 +1,157 @@
/**************************************************************************/
/* freedesktop_at_spi_monitor.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "freedesktop_at_spi_monitor.h"
#ifdef DBUS_ENABLED
#include "core/os/os.h"
#ifdef SOWRAP_ENABLED
#include "dbus-so_wrap.h"
#else
#include <dbus/dbus.h>
#endif
#include <unistd.h>
#define BUS_OBJECT_NAME "org.a11y.Bus"
#define BUS_OBJECT_PATH "/org/a11y/bus"
#define BUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
void FreeDesktopAtSPIMonitor::monitor_thread_func(void *p_userdata) {
FreeDesktopAtSPIMonitor *mon = (FreeDesktopAtSPIMonitor *)p_userdata;
DBusError error;
dbus_error_init(&error);
DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error)) {
dbus_error_free(&error);
mon->supported.clear();
return;
}
static const char *iface = "org.a11y.Status";
static const char *member = "IsEnabled";
while (!mon->exit_thread.is_set()) {
DBusMessage *message = dbus_message_new_method_call(BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_PROPERTIES, "Get");
dbus_message_append_args(
message,
DBUS_TYPE_STRING, &iface,
DBUS_TYPE_STRING, &member,
DBUS_TYPE_INVALID);
DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error);
dbus_message_unref(message);
if (!dbus_error_is_set(&error)) {
DBusMessageIter iter, iter_variant, iter_struct;
dbus_bool_t result;
dbus_message_iter_init(reply, &iter);
dbus_message_iter_recurse(&iter, &iter_variant);
switch (dbus_message_iter_get_arg_type(&iter_variant)) {
case DBUS_TYPE_STRUCT: {
dbus_message_iter_recurse(&iter_variant, &iter_struct);
if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
dbus_message_iter_get_basic(&iter_struct, &result);
if (result) {
mon->sr_enabled.set();
} else {
mon->sr_enabled.clear();
}
}
} break;
case DBUS_TYPE_BOOLEAN: {
dbus_message_iter_get_basic(&iter_variant, &result);
if (result) {
mon->sr_enabled.set();
} else {
mon->sr_enabled.clear();
}
} break;
default:
break;
}
dbus_message_unref(reply);
} else {
dbus_error_free(&error);
}
usleep(50000);
}
dbus_connection_unref(bus);
}
FreeDesktopAtSPIMonitor::FreeDesktopAtSPIMonitor() {
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
int dylibloader_verbose = 1;
#else
int dylibloader_verbose = 0;
#endif
if (initialize_dbus(dylibloader_verbose) != 0) {
print_verbose("AT-SPI2: Failed to load DBus library!");
supported.clear();
return;
}
#endif
bool ver_ok = false;
int version_major = 0;
int version_minor = 0;
int version_rev = 0;
dbus_get_version(&version_major, &version_minor, &version_rev);
ver_ok = (version_major == 1 && version_minor >= 10) || (version_major > 1); // 1.10.0
print_verbose(vformat("AT-SPI2: DBus %d.%d.%d detected.", version_major, version_minor, version_rev));
if (!ver_ok) {
print_verbose("AT-SPI2: Unsupported DBus library version!");
supported.clear();
return;
}
supported.set();
sr_enabled.clear();
exit_thread.clear();
thread.start(FreeDesktopAtSPIMonitor::monitor_thread_func, this);
}
FreeDesktopAtSPIMonitor::~FreeDesktopAtSPIMonitor() {
exit_thread.set();
if (thread.is_started()) {
thread.wait_to_finish();
}
}
#endif // DBUS_ENABLED

View file

@ -0,0 +1,56 @@
/**************************************************************************/
/* freedesktop_at_spi_monitor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifdef DBUS_ENABLED
#include "core/os/thread.h"
#include "core/os/thread_safe.h"
class FreeDesktopAtSPIMonitor {
private:
Thread thread;
SafeFlag exit_thread;
SafeFlag sr_enabled;
SafeFlag supported;
static void monitor_thread_func(void *p_userdata);
public:
FreeDesktopAtSPIMonitor();
~FreeDesktopAtSPIMonitor();
bool is_supported() { return supported.is_set(); }
bool is_active() { return sr_enabled.is_set(); }
};
#endif // DBUS_ENABLED

View file

@ -101,6 +101,11 @@ bool FreeDesktopPortalDesktop::try_parse_variant(DBusMessage *p_reply_message, R
return false;
}
dbus_message_iter_get_basic(&iter[2], r_value);
} else if (p_type == VAR_TYPE_BOOL) {
if (dbus_message_iter_get_arg_type(&iter[2]) != DBUS_TYPE_BOOLEAN) {
return false;
}
dbus_message_iter_get_basic(&iter[2], r_value);
}
return true;
}
@ -177,6 +182,18 @@ Color FreeDesktopPortalDesktop::get_appearance_accent_color() {
}
}
uint32_t FreeDesktopPortalDesktop::get_high_contrast() {
if (unsupported) {
return -1;
}
dbus_bool_t value = false;
if (read_setting("org.gnome.desktop.a11y.interface", "high-contrast", VAR_TYPE_BOOL, &value)) {
return value;
}
return -1;
}
static const char *cs_empty = "";
void FreeDesktopPortalDesktop::append_dbus_string(DBusMessageIter *p_iter, const String &p_string) {

View file

@ -46,6 +46,7 @@ private:
enum ReadVariantType {
VAR_TYPE_UINT32, // u
VAR_TYPE_BOOL, // b
VAR_TYPE_COLOR, // (ddd)
};
@ -135,6 +136,12 @@ public:
system_theme_changed = p_system_theme_changed;
}
// Retrieve high-contrast setting.
// -1: Unknown.
// 0: Disabled.
// 1: Enabled.
uint32_t get_high_contrast();
// org.freedesktop.portal.Screenshot methods.
bool color_picker(const String &p_xid, const Callable &p_callback);
};

View file

@ -39,6 +39,8 @@
#define DEBUG_LOG_WAYLAND(...)
#endif
#include "servers/rendering/dummy/rasterizer_dummy.h"
#ifdef VULKAN_ENABLED
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
@ -50,6 +52,10 @@
#include "wayland/egl_manager_wayland_gles.h"
#endif
#ifdef ACCESSKIT_ENABLED
#include "drivers/accesskit/accessibility_driver_accesskit.h"
#endif
#define WAYLAND_MAX_FRAME_TIME_US (1'000'000)
String DisplayServerWayland::_get_app_id_from_context(Context p_context) {
@ -201,6 +207,12 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
} break;
#endif
#ifdef ACCESSKIT_ENABLED
case FEATURE_ACCESSIBILITY_SCREEN_READER: {
return (accessibility_driver != nullptr);
} break;
#endif
default: {
return false;
}
@ -689,6 +701,16 @@ DisplayServer::WindowID DisplayServerWayland::create_sub_window(WindowMode p_mod
wd.flags = p_flags;
wd.vsync_mode = p_vsync_mode;
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver && !accessibility_driver->window_create(wd.id, nullptr)) {
if (OS::get_singleton()->is_stdout_verbose()) {
ERR_PRINT("Can't create an accessibility adapter for window, accessibility support disabled!");
}
memdelete(accessibility_driver);
accessibility_driver = nullptr;
}
#endif
// NOTE: Remember to clear its position if this window will be a toplevel. We
// can only know once we show it.
wd.rect = p_rect;
@ -840,6 +862,12 @@ void DisplayServerWayland::delete_sub_window(WindowID p_window_id) {
popup_menu_list.pop_back();
}
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->window_destroy(p_window_id);
}
#endif
if (wd.visible) {
#ifdef VULKAN_ENABLED
if (rendering_device) {
@ -1284,6 +1312,22 @@ void DisplayServerWayland::window_set_ime_position(const Point2i &p_pos, Display
wayland_thread.window_set_ime_position(p_pos, p_window_id);
}
int DisplayServerWayland::accessibility_should_increase_contrast() const {
#ifdef DBUS_ENABLED
return portal_desktop->get_high_contrast();
#endif
return -1;
}
int DisplayServerWayland::accessibility_screen_reader_active() const {
#ifdef DBUS_ENABLED
if (atspi_monitor->is_supported()) {
return atspi_monitor->is_active();
}
#endif
return -1;
}
Point2i DisplayServerWayland::ime_get_selection() const {
return ime_selection;
}
@ -1557,14 +1601,24 @@ void DisplayServerWayland::process_events() {
}
Ref<WaylandThread::WindowEventMessage> winev_msg = msg;
if (winev_msg.is_valid()) {
if (winev_msg.is_valid() && windows.has(winev_msg->id)) {
_send_window_event(winev_msg->event, winev_msg->id);
if (winev_msg->event == WINDOW_EVENT_FOCUS_IN) {
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->accessibility_set_window_focused(winev_msg->id, true);
}
#endif
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
}
} else if (winev_msg->event == WINDOW_EVENT_FOCUS_OUT) {
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->accessibility_set_window_focused(winev_msg->id, false);
}
#endif
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
@ -1775,6 +1829,7 @@ Vector<String> DisplayServerWayland::get_rendering_drivers_func() {
drivers.push_back("opengl3");
drivers.push_back("opengl3_es");
#endif
drivers.push_back("dummy");
return drivers;
}
@ -1828,11 +1883,26 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_get_mode() != DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
accessibility_driver = memnew(AccessibilityDriverAccessKit);
if (accessibility_driver->init() != OK) {
memdelete(accessibility_driver);
accessibility_driver = nullptr;
}
}
#endif
rendering_driver = p_rendering_driver;
bool driver_found = false;
String executable_name = OS::get_singleton()->get_executable_path().get_file();
if (rendering_driver == "dummy") {
RasterizerDummy::make_current();
driver_found = true;
}
#ifdef RD_ENABLED
#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
@ -2021,6 +2091,7 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
#ifdef DBUS_ENABLED
portal_desktop = memnew(FreeDesktopPortalDesktop);
atspi_monitor = memnew(FreeDesktopAtSPIMonitor);
screensaver = memnew(FreeDesktopScreenSaver);
#endif // DBUS_ENABLED
@ -2045,12 +2116,17 @@ DisplayServerWayland::~DisplayServerWayland() {
if (!window_get_flag(WINDOW_FLAG_POPUP_WM_HINT, id)) {
toplevels.push_back(id);
#ifdef ACCESSKIT_ENABLED
} else if (accessibility_driver) {
accessibility_driver->window_destroy(id);
#endif
}
}
for (WindowID &id : toplevels) {
delete_sub_window(id);
}
windows.clear();
wayland_thread.destroy();
@ -2071,9 +2147,16 @@ DisplayServerWayland::~DisplayServerWayland() {
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
memdelete(accessibility_driver);
}
#endif
#ifdef DBUS_ENABLED
if (portal_desktop) {
memdelete(portal_desktop);
memdelete(atspi_monitor);
memdelete(screensaver);
}
#endif

View file

@ -52,6 +52,7 @@
#endif
#ifdef DBUS_ENABLED
#include "freedesktop_at_spi_monitor.h"
#include "freedesktop_portal_desktop.h"
#include "freedesktop_screensaver.h"
#endif
@ -167,6 +168,7 @@ class DisplayServerWayland : public DisplayServer {
#if DBUS_ENABLED
FreeDesktopPortalDesktop *portal_desktop = nullptr;
FreeDesktopAtSPIMonitor *atspi_monitor = nullptr;
FreeDesktopScreenSaver *screensaver = nullptr;
bool screensaver_inhibited = false;
@ -307,6 +309,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window_id = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window_id = MAIN_WINDOW_ID) override;
virtual int accessibility_should_increase_contrast() const override;
virtual int accessibility_screen_reader_active() const override;
virtual Point2i ime_get_selection() const override;
virtual String ime_get_text() const override;

View file

@ -39,9 +39,12 @@
#include "core/math/math_funcs.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "main/main.h"
#include "servers/rendering/dummy/rasterizer_dummy.h"
#if defined(VULKAN_ENABLED)
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
@ -50,6 +53,10 @@
#include "drivers/gles3/rasterizer_gles3.h"
#endif
#ifdef ACCESSKIT_ENABLED
#include "drivers/accesskit/accessibility_driver_accesskit.h"
#endif
#include <dlfcn.h>
#include <limits.h>
#include <stdio.h>
@ -169,6 +176,12 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
} break;
#endif
#ifdef ACCESSKIT_ENABLED
case FEATURE_ACCESSIBILITY_SCREEN_READER: {
return (accessibility_driver != nullptr);
} break;
#endif
default: {
return false;
}
@ -1943,6 +1956,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->window_destroy(p_id);
}
#endif
if (wd.xic) {
XDestroyIC(wd.xic);
wd.xic = nullptr;
@ -3337,6 +3356,22 @@ void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_
}
}
int DisplayServerX11::accessibility_should_increase_contrast() const {
#ifdef DBUS_ENABLED
return portal_desktop->get_high_contrast();
#endif
return -1;
}
int DisplayServerX11::accessibility_screen_reader_active() const {
#ifdef DBUS_ENABLED
if (atspi_monitor->is_supported()) {
return atspi_monitor->is_active();
}
#endif
return -1;
}
Point2i DisplayServerX11::ime_get_selection() const {
return im_selection;
}
@ -4987,6 +5022,11 @@ void DisplayServerX11::process_events() {
static unsigned int focus_order = 0;
wd.focus_order = ++focus_order;
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->accessibility_set_window_focused(window_id, true);
}
#endif
_send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
if (mouse_mode_grab) {
@ -5038,6 +5078,11 @@ void DisplayServerX11::process_events() {
wd.focused = false;
Input::get_singleton()->release_pressed_events();
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->accessibility_set_window_focused(window_id, false);
}
#endif
_send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
if (mouse_mode_grab) {
@ -6139,6 +6184,7 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
drivers.push_back("opengl3");
drivers.push_back("opengl3_es");
#endif
drivers.push_back("dummy");
return drivers;
}
@ -6287,6 +6333,15 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
if (dead_tbl && xkb_loaded_v05p) {
wd.xkb_state = xkb_compose_state_new(dead_tbl, XKB_COMPOSE_STATE_NO_FLAGS);
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver && !accessibility_driver->window_create(id, nullptr)) {
if (OS::get_singleton()->is_stdout_verbose()) {
ERR_PRINT("Can't create an accessibility adapter for window, accessibility support disabled!");
}
memdelete(accessibility_driver);
accessibility_driver = nullptr;
}
#endif
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@ -6874,6 +6929,16 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_get_mode() != DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
accessibility_driver = memnew(AccessibilityDriverAccessKit);
if (accessibility_driver->init() != OK) {
memdelete(accessibility_driver);
accessibility_driver = nullptr;
}
}
#endif
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
@ -6883,6 +6948,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
// Initialize context and rendering device.
if (rendering_driver == "dummy") {
RasterizerDummy::make_current();
driver_found = true;
}
#if defined(RD_ENABLED)
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
@ -7213,8 +7283,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
portal_desktop = memnew(FreeDesktopPortalDesktop);
atspi_monitor = memnew(FreeDesktopAtSPIMonitor);
#endif // DBUS_ENABLED
XSetErrorHandler(&default_window_error_handler);
r_error = OK;
@ -7254,6 +7324,12 @@ DisplayServerX11::~DisplayServerX11() {
}
#endif
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
accessibility_driver->window_destroy(E.key);
}
#endif
WindowData &wd = E.value;
if (wd.xic) {
XDestroyIC(wd.xic);
@ -7328,7 +7404,11 @@ DisplayServerX11::~DisplayServerX11() {
if (xmbstring) {
memfree(xmbstring);
}
#ifdef ACCESSKIT_ENABLED
if (accessibility_driver) {
memdelete(accessibility_driver);
}
#endif
#ifdef SPEECHD_ENABLED
if (tts) {
memdelete(tts);
@ -7338,6 +7418,7 @@ DisplayServerX11::~DisplayServerX11() {
#ifdef DBUS_ENABLED
memdelete(screensaver);
memdelete(portal_desktop);
memdelete(atspi_monitor);
#endif
}

View file

@ -65,6 +65,7 @@
#endif
#if defined(DBUS_ENABLED)
#include "freedesktop_at_spi_monitor.h"
#include "freedesktop_portal_desktop.h"
#include "freedesktop_screensaver.h"
#endif
@ -159,6 +160,7 @@ class DisplayServerX11 : public DisplayServer {
#if defined(DBUS_ENABLED)
FreeDesktopPortalDesktop *portal_desktop = nullptr;
FreeDesktopAtSPIMonitor *atspi_monitor = nullptr;
#endif
struct WindowData {
@ -536,6 +538,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override;
virtual int accessibility_should_increase_contrast() const override;
virtual int accessibility_screen_reader_active() const override;
virtual Point2i ime_get_selection() const override;
virtual String ime_get_text() const override;