You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-20 14:45:44 +00:00
Base accessibility API.
This commit is contained in:
@@ -48,6 +48,8 @@ void Window::set_root_layout_direction(int p_root_dir) {
|
||||
|
||||
// Dynamic properties.
|
||||
|
||||
Window *Window::focused_window = nullptr;
|
||||
|
||||
bool Window::_set(const StringName &p_name, const Variant &p_value) {
|
||||
ERR_MAIN_THREAD_GUARD_V(false);
|
||||
String name = p_name;
|
||||
@@ -314,6 +316,7 @@ void Window::set_title(const String &p_title) {
|
||||
EngineDebugger::get_singleton()->send_message("window:title", arr);
|
||||
}
|
||||
#endif
|
||||
queue_accessibility_update();
|
||||
}
|
||||
|
||||
String Window::get_title() const {
|
||||
@@ -687,6 +690,11 @@ void Window::_make_window() {
|
||||
}
|
||||
}
|
||||
|
||||
if (get_tree() && get_tree()->is_accessibility_supported()) {
|
||||
get_tree()->_accessibility_force_update();
|
||||
_accessibility_notify_enter(this);
|
||||
}
|
||||
|
||||
_update_window_callbacks();
|
||||
|
||||
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
|
||||
@@ -718,6 +726,10 @@ void Window::_clear_window() {
|
||||
|
||||
_update_from_window();
|
||||
|
||||
if (get_tree() && get_tree()->is_accessibility_supported()) {
|
||||
_accessibility_notify_exit(this);
|
||||
}
|
||||
|
||||
DisplayServer::get_singleton()->delete_sub_window(window_id);
|
||||
window_id = DisplayServer::INVALID_WINDOW_ID;
|
||||
|
||||
@@ -749,6 +761,14 @@ void Window::_rect_changed_callback(const Rect2i &p_callback) {
|
||||
size = p_callback.size;
|
||||
_update_viewport_size();
|
||||
}
|
||||
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
|
||||
Vector2 sz_out = DisplayServer::get_singleton()->window_get_size_with_decorations(window_id);
|
||||
Vector2 pos_out = DisplayServer::get_singleton()->window_get_position_with_decorations(window_id);
|
||||
Vector2 sz_in = DisplayServer::get_singleton()->window_get_size(window_id);
|
||||
Vector2 pos_in = DisplayServer::get_singleton()->window_get_position(window_id);
|
||||
DisplayServer::get_singleton()->accessibility_set_window_rect(window_id, Rect2(pos_out, sz_out), Rect2(pos_in, sz_in));
|
||||
}
|
||||
queue_accessibility_update();
|
||||
}
|
||||
|
||||
void Window::_propagate_window_notification(Node *p_node, int p_notification) {
|
||||
@@ -807,12 +827,15 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
|
||||
} break;
|
||||
case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
|
||||
focused = true;
|
||||
focused_window = this;
|
||||
_propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_IN);
|
||||
emit_signal(SceneStringName(focus_entered));
|
||||
|
||||
} break;
|
||||
case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
|
||||
focused = false;
|
||||
if (focused_window == this) {
|
||||
focused_window = nullptr;
|
||||
}
|
||||
_propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_OUT);
|
||||
emit_signal(SceneStringName(focus_exited));
|
||||
} break;
|
||||
@@ -868,6 +891,36 @@ void Window::hide() {
|
||||
set_visible(false);
|
||||
}
|
||||
|
||||
void Window::_accessibility_notify_enter(Node *p_node) {
|
||||
p_node->queue_accessibility_update();
|
||||
|
||||
if (p_node != this) {
|
||||
const Window *window = Object::cast_to<Window>(p_node);
|
||||
if (window && !window->is_embedded()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
_accessibility_notify_enter(p_node->get_child(i));
|
||||
}
|
||||
}
|
||||
|
||||
void Window::_accessibility_notify_exit(Node *p_node) {
|
||||
p_node->notification(Node::NOTIFICATION_ACCESSIBILITY_INVALIDATE);
|
||||
|
||||
if (p_node != this) {
|
||||
const Window *window = Object::cast_to<Window>(p_node);
|
||||
if (window && !window->is_embedded()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
_accessibility_notify_exit(p_node->get_child(i));
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_visible(bool p_visible) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
if (visible == p_visible) {
|
||||
@@ -907,9 +960,11 @@ void Window::set_visible(bool p_visible) {
|
||||
}
|
||||
}
|
||||
embedder->_sub_window_register(this);
|
||||
embedder->queue_accessibility_update();
|
||||
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
|
||||
} else {
|
||||
embedder->_sub_window_remove(this);
|
||||
embedder->queue_accessibility_update();
|
||||
embedder = nullptr;
|
||||
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
|
||||
}
|
||||
@@ -918,7 +973,11 @@ void Window::set_visible(bool p_visible) {
|
||||
|
||||
if (!visible) {
|
||||
focused = false;
|
||||
if (focused_window == this) {
|
||||
focused_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
notification(NOTIFICATION_VISIBILITY_CHANGED);
|
||||
emit_signal(SceneStringName(visibility_changed));
|
||||
|
||||
@@ -1332,9 +1391,78 @@ Viewport *Window::get_embedder() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RID Window::get_accessibility_element() const {
|
||||
if (is_part_of_edited_scene()) {
|
||||
return RID();
|
||||
}
|
||||
if (get_embedder()) {
|
||||
return Node::get_accessibility_element();
|
||||
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
|
||||
return DisplayServer::get_singleton()->accessibility_get_window_root(window_id);
|
||||
} else {
|
||||
return RID();
|
||||
}
|
||||
}
|
||||
|
||||
RID Window::get_focused_accessibility_element() const {
|
||||
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
|
||||
if (get_child_count() > 0) {
|
||||
return get_child(0)->get_focused_accessibility_element(); // Try scene tree root node.
|
||||
}
|
||||
}
|
||||
return Node::get_focused_accessibility_element();
|
||||
}
|
||||
|
||||
void Window::_notification(int p_what) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_INVALIDATE: {
|
||||
accessibility_title_element = RID();
|
||||
accessibility_announcement_element = RID();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_WINDOW);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, tr_title);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_MODAL, exclusive);
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_FOCUS, callable_mp(this, &Window::_accessibility_action_grab_focus));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_HIDDEN, !visible);
|
||||
|
||||
if (get_embedder()) {
|
||||
Control *parent_ctrl = Object::cast_to<Control>(get_parent());
|
||||
Transform2D parent_tr = parent_ctrl ? parent_ctrl->get_global_transform() : Transform2D();
|
||||
Transform2D tr;
|
||||
tr.set_origin(position);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_transform(ae, parent_tr.affine_inverse() * tr);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_bounds(ae, Rect2(Point2(), size));
|
||||
|
||||
if (accessibility_title_element.is_null()) {
|
||||
accessibility_title_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_TITLE_BAR);
|
||||
}
|
||||
|
||||
int w = get_theme_constant(SNAME("title_height"));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(accessibility_title_element, tr_title);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_bounds(accessibility_title_element, Rect2(Vector2(0, -w), Size2(size.x, w)));
|
||||
} else {
|
||||
DisplayServer::get_singleton()->accessibility_update_set_transform(ae, Transform2D());
|
||||
DisplayServer::get_singleton()->accessibility_update_set_bounds(ae, Rect2(Point2(), size));
|
||||
|
||||
if (accessibility_announcement_element.is_null()) {
|
||||
accessibility_announcement_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
}
|
||||
|
||||
if (announcement.is_empty()) {
|
||||
DisplayServer::get_singleton()->accessibility_update_set_live(accessibility_announcement_element, DisplayServer::LIVE_OFF);
|
||||
} else {
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(accessibility_announcement_element, announcement);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_live(accessibility_announcement_element, DisplayServer::LIVE_ASSERTIVE);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_POSTINITIALIZE: {
|
||||
initialized = true;
|
||||
|
||||
@@ -1389,6 +1517,7 @@ void Window::_notification(int p_what) {
|
||||
// It's the root window!
|
||||
visible = true; // Always visible.
|
||||
window_id = DisplayServer::MAIN_WINDOW_ID;
|
||||
focused_window = this;
|
||||
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
|
||||
_update_from_window();
|
||||
// Since this window already exists (created on start), we must update pos and size from it.
|
||||
@@ -1467,6 +1596,7 @@ void Window::_notification(int p_what) {
|
||||
}
|
||||
}
|
||||
}
|
||||
queue_accessibility_update();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
@@ -1485,6 +1615,9 @@ void Window::_notification(int p_what) {
|
||||
|
||||
set_theme_context(nullptr, false);
|
||||
|
||||
accessibility_title_element = RID();
|
||||
accessibility_announcement_element = RID();
|
||||
|
||||
if (transient) {
|
||||
_clear_transient();
|
||||
}
|
||||
@@ -1604,7 +1737,12 @@ bool Window::is_using_font_oversampling() const {
|
||||
|
||||
DisplayServer::WindowID Window::get_window_id() const {
|
||||
ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
|
||||
if (embedder) {
|
||||
if (get_embedder()) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (is_part_of_edited_scene()) {
|
||||
return DisplayServer::MAIN_WINDOW_ID;
|
||||
}
|
||||
#endif
|
||||
return parent->get_window_id();
|
||||
}
|
||||
return window_id;
|
||||
@@ -2080,6 +2218,11 @@ Rect2i Window::get_usable_parent_rect() const {
|
||||
return parent_rect;
|
||||
}
|
||||
|
||||
void Window::accessibility_announcement(const String &p_announcement) {
|
||||
announcement = p_announcement;
|
||||
queue_accessibility_update();
|
||||
}
|
||||
|
||||
void Window::add_child_notify(Node *p_child) {
|
||||
if (is_inside_tree() && wrap_controls) {
|
||||
child_controls_changed();
|
||||
@@ -2906,8 +3049,6 @@ void Window::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
|
||||
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_window_id"), &Window::get_window_id);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_initial_position", "initial_position"), &Window::set_initial_position);
|
||||
ClassDB::bind_method(D_METHOD("get_initial_position"), &Window::get_initial_position);
|
||||
|
||||
@@ -3055,6 +3196,10 @@ void Window::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font);
|
||||
ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_window_id"), &Window::get_window_id);
|
||||
|
||||
ClassDB::bind_static_method("Window", D_METHOD("get_focused_window"), &Window::get_focused_window);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
|
||||
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
|
||||
ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);
|
||||
@@ -3227,6 +3372,9 @@ Window::Window() {
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
if (focused_window == this) {
|
||||
focused_window = nullptr;
|
||||
}
|
||||
memdelete(theme_owner);
|
||||
|
||||
// Resources need to be disconnected.
|
||||
|
||||
Reference in New Issue
Block a user