Merge pull request #76829 from bruvzg/ac_kit_direct
Implement screen reader support using AccessKit library.
This commit is contained in:
commit
e6a61b1ecc
305 changed files with 32447 additions and 300 deletions
|
|
@ -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"]:
|
||||
|
|
|
|||
|
|
@ -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"]:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
157
platform/linuxbsd/freedesktop_at_spi_monitor.cpp
Normal file
157
platform/linuxbsd/freedesktop_at_spi_monitor.cpp
Normal 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
|
||||
56
platform/linuxbsd/freedesktop_at_spi_monitor.h
Normal file
56
platform/linuxbsd/freedesktop_at_spi_monitor.h
Normal 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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue