Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Additional updates |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | tka11y |
Files: | files | file ages | folders |
SHA3-256: |
ee4e1c5387a0b60da30aa5b5a10d03b7 |
User & Date: | kevin_walzer 2025-07-25 03:06:00.471 |
Context
2025-07-25
| ||
03:06 | Additional updates Leaf check-in: ee4e1c53 user: kevin_walzer tags: tka11y | |
00:52 | Additional refinements to ensure root accessible object persists check-in: 545436c5 user: kevin_walzer tags: tka11y | |
Changes
Changes to library/accessibility.tcl.
︙ | ︙ | |||
681 682 683 684 685 686 687 688 689 690 691 692 693 694 | bind Canvas <Map> {+::tk::accessible::acc_help %W "The canvas widget is not accessible."} bind Scrollbar <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to move the scrollbar."} bind TScrollbar <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to move the scrollbar."} bind Menubutton <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to pop up the menu."} bind TMenubutton <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to pop up the menu."} bind TNotebook <Map> {+::tk::accessible::acc_help %W "Use the Tab and Right/Left arrow keys to navigate between notebook tabs."} bind Text <Map> {+::tk::accessible::acc_help %W "Use normal keyboard shortcuts to navigate the text widget."} # Finally, export the main commands. namespace export acc_role acc_name acc_description acc_value acc_state acc_action acc_help get_acc_role get_acc_name get_acc_description get_acc_value get_acc_state get_acc_action get_acc_help add_acc_object emit_selection_change check_screenreader emit_focus_change namespace ensemble create } } | > > | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 | bind Canvas <Map> {+::tk::accessible::acc_help %W "The canvas widget is not accessible."} bind Scrollbar <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to move the scrollbar."} bind TScrollbar <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to move the scrollbar."} bind Menubutton <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to pop up the menu."} bind TMenubutton <Map> {+::tk::accessible::acc_help %W "Use the touchpad or mouse wheel to pop up the menu."} bind TNotebook <Map> {+::tk::accessible::acc_help %W "Use the Tab and Right/Left arrow keys to navigate between notebook tabs."} bind Text <Map> {+::tk::accessible::acc_help %W "Use normal keyboard shortcuts to navigate the text widget."} ::tk::accessible::add_acc_object . # Finally, export the main commands. namespace export acc_role acc_name acc_description acc_value acc_state acc_action acc_help get_acc_role get_acc_name get_acc_description get_acc_value get_acc_state get_acc_action get_acc_help add_acc_object emit_selection_change check_screenreader emit_focus_change namespace ensemble create } } |
︙ | ︙ |
Changes to unix/tkUnixAccessibility.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 | gboolean cache_dirty; gboolean is_destroyed; } TkAtkAccessible; typedef struct _TkAtkAccessibleClass { AtkObjectClass parent_class; } TkAtkAccessibleClass; typedef struct AtkRoleMap { const char *tkrole; AtkRole atkrole; } AtkRoleMap; struct AtkRoleMap roleMap[] = { | > > > > > > > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | gboolean cache_dirty; gboolean is_destroyed; } TkAtkAccessible; typedef struct _TkAtkAccessibleClass { AtkObjectClass parent_class; } TkAtkAccessibleClass; typedef struct _CustomAtkUtil { AtkUtil parent; } CustomAtkUtil; typedef struct _CustomAtkUtilClass { AtkUtilClass parent_class; } CustomAtkUtilClass; typedef struct AtkRoleMap { const char *tkrole; AtkRole atkrole; } AtkRoleMap; struct AtkRoleMap roleMap[] = { |
︙ | ︙ | |||
252 253 254 255 256 257 258 259 260 261 262 263 264 265 | static void tk_get_extents(AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type); static gboolean RunOnMainThreadCallback(gpointer user_data); void RunOnMainThread(void (*func)(void *), void *data); static void GtkEventLoop(ClientData clientData); void InstallGtkEventLoop(void); static AtkObject *tk_util_get_root(void); AtkObject *tk_create_root_accessible(void); static AtkObject *tk_ref_child(AtkObject *obj, guint i); static gint tk_get_n_children(AtkObject *obj); static AtkRole tk_get_role(AtkObject *obj); static AtkRole GetAtkRoleForWidget_core(Tk_Window win); static gchar *sanitize_utf8(const gchar *str); static const gchar *tk_get_name_core(AtkObject *obj); static void tk_set_name_core(AtkObject *obj, const gchar *name); | > > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | static void tk_get_extents(AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type); static gboolean RunOnMainThreadCallback(gpointer user_data); void RunOnMainThread(void (*func)(void *), void *data); static void GtkEventLoop(ClientData clientData); void InstallGtkEventLoop(void); static AtkObject *tk_util_get_root(void); AtkObject *tk_create_root_accessible(void); static GType custom_atk_util_get_type(void); static AtkObject* custom_atk_util_get_root(void); static AtkObject *tk_ref_child(AtkObject *obj, guint i); static gint tk_get_n_children(AtkObject *obj); static AtkRole tk_get_role(AtkObject *obj); static AtkRole GetAtkRoleForWidget_core(Tk_Window win); static gchar *sanitize_utf8(const gchar *str); static const gchar *tk_get_name_core(AtkObject *obj); static void tk_set_name_core(AtkObject *obj, const gchar *name); |
︙ | ︙ | |||
305 306 307 308 309 310 311 | * *---------------------------------------------------------------------- */ /* * Functions to initialize and manage the parent Atk class and object instances. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | * *---------------------------------------------------------------------- */ /* * Functions to initialize and manage the parent Atk class and object instances. */ /* Custom AtkUtil class initialization. */ static void custom_atk_util_class_init(CustomAtkUtilClass *klass) { AtkUtilClass *util_class = ATK_UTIL_CLASS(klass); util_class->get_root = custom_atk_util_get_root; } /* GType registration for CustomAtkUtil. */ static GType custom_atk_util_get_type(void) { static GType type = 0; if (!type) { static const GTypeInfo tinfo = { sizeof(CustomAtkUtilClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) custom_atk_util_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(CustomAtkUtil), 0, /* n_preallocs */ NULL, /* instance_init */ NULL /* value_table */ }; type = g_type_register_static(ATK_TYPE_UTIL, "CustomAtkUtil", &tinfo, 0); } return type; } /* Custom get_root implementation to return tk_root_accessible */ static AtkObject* custom_atk_util_get_root(void) { g_mutex_lock(&root_accessible_mutex); if (tk_root_accessible) { AtkObject *root = tk_root_accessible; g_object_ref(root); g_mutex_unlock(&root_accessible_mutex); g_debug("custom_atk_util_get_root: Returning tk_root_accessible %p", root); return root; } g_mutex_unlock(&root_accessible_mutex); g_debug("custom_atk_util_get_root: tk_root_accessible is NULL"); return NULL; } static void tk_atk_accessible_init(TkAtkAccessible *self) { if (!g_type_is_a(TK_ATK_TYPE_ACCESSIBLE, ATK_TYPE_OBJECT)) { g_error("TK_ATK_TYPE_ACCESSIBLE is not properly registered"); } self->tkwin = NULL; self->interp = NULL; self->path = NULL; |
︙ | ︙ | |||
381 382 383 384 385 386 387 388 389 390 391 392 393 394 | atk_class->get_name = tk_get_name_core; atk_class->get_description = tk_get_description_core; atk_class->get_role = tk_get_role; atk_class->ref_state_set = tk_ref_state_set_core; atk_class->get_n_children = tk_get_n_children; atk_class->ref_child = tk_ref_child; } /* * Functions to map ATK component interface to Tk. */ static void tk_get_extents(AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { ExtentsData *data = g_new(ExtentsData, 1); data->component = component; | > > | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | atk_class->get_name = tk_get_name_core; atk_class->get_description = tk_get_description_core; atk_class->get_role = tk_get_role; atk_class->ref_state_set = tk_ref_state_set_core; atk_class->get_n_children = tk_get_n_children; atk_class->ref_child = tk_ref_child; } /* * Functions to map ATK component interface to Tk. */ static void tk_get_extents(AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { ExtentsData *data = g_new(ExtentsData, 1); data->component = component; |
︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 | AtkObject *tk_create_root_accessible(void) { g_mutex_lock(&root_accessible_mutex); if (tk_root_accessible) { AtkObject *root = tk_root_accessible; g_object_ref(root); g_mutex_unlock(&root_accessible_mutex); | | > < < < < | < | | > > > > > > > | > > | | > > > | 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | AtkObject *tk_create_root_accessible(void) { g_mutex_lock(&root_accessible_mutex); if (tk_root_accessible) { AtkObject *root = tk_root_accessible; g_object_ref(root); g_mutex_unlock(&root_accessible_mutex); g_debug("tk_create_root_accessible: Returning existing root %p (ref_count=%d)", root, G_OBJECT(root)->ref_count); return root; } TkAtkAccessible *acc = g_object_new(TK_ATK_TYPE_ACCESSIBLE, NULL); if (!acc) { g_warning("tk_create_root_accessible: Failed to create root accessible object"); g_mutex_unlock(&root_accessible_mutex); return NULL; } AtkObject *obj = ATK_OBJECT(acc); atk_object_initialize(obj, NULL); atk_object_set_role(obj, ATK_ROLE_APPLICATION); atk_object_set_name(obj, "Tk Application"); /* Register with ATK map */ InitAtkTkMapping(); if (!tk_to_atk_map) { g_warning("tk_create_root_accessible: tk_to_atk_map is NULL"); g_object_unref(obj); g_mutex_unlock(&root_accessible_mutex); return NULL; } g_object_ref(obj); /* Permanent reference */ tk_root_accessible = obj; g_mutex_lock(&atk_map_mutex); g_hash_table_insert(tk_to_atk_map, NULL, obj); g_mutex_unlock(&atk_map_mutex); g_debug("tk_create_root_accessible: Created and registered root %p (ref_count=%d)", obj, G_OBJECT(obj)->ref_count); g_mutex_unlock(&root_accessible_mutex); /* Explicitly notify AT-SPI of the root object */ if (atk_get_root() == obj) { g_debug("tk_create_root_accessible: Root object %p successfully registered with atk_get_root", obj); } else { g_warning("tk_create_root_accessible: atk_get_root() does not return tk_root_accessible %p", obj); } /* Emit signal to notify AT-SPI of the new root */ SignalData *signal_data = g_new(SignalData, 1); signal_data->obj = obj; signal_data->signal_name = "children-changed"; signal_data->data = NULL; RunOnMainThread(ThreadSafe_EmitSignal, signal_data); return g_object_ref(obj); } AtkObject *atk_get_root(void) { return tk_util_get_root(); } /* Atk-Tk object creation with proper parent relationship. */ |
︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 | * *---------------------------------------------------------------------- */ #ifdef USE_ATK int TkAtkAccessibility_Init(Tcl_Interp *interp) { | | | > | | > | > > > > > | > > > > > > > > > > > | > > | > > | > > | > | > > > | > | > | < | 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 | * *---------------------------------------------------------------------- */ #ifdef USE_ATK int TkAtkAccessibility_Init(Tcl_Interp *interp) { /* Initialize mutexes for thread safety */ g_mutex_init(&toplevel_list_mutex); g_mutex_init(&root_accessible_mutex); g_mutex_init(&atk_map_mutex); /* Set required environment variables for ATK bridge */ g_setenv("GTK_MODULES", "gail:atk-bridge", FALSE); g_setenv("NO_AT_BRIDGE", "0", FALSE); g_debug("TkAtkAccessibility_Init: Environment variables set for ATK bridge"); /* Initialize tk_to_atk_map early */ InitAtkTkMapping(); if (!tk_to_atk_map) { Tcl_SetResult(interp, "Failed to initialize tk_to_atk_map", TCL_STATIC); return TCL_ERROR; } g_debug("TkAtkAccessibility_Init: tk_to_atk_map initialized"); /* Initialize GObject type system (noop since GLib 2.36) */ g_type_init(); /* Register custom AtkUtil class */ GType util_type = custom_atk_util_get_type(); g_type_class_unref(g_type_class_ref(util_type)); g_debug("TkAtkAccessibility_Init: Custom AtkUtil registered with GType %lu", (gulong)util_type); /* Create the root accessible object */ AtkObject *root = tk_create_root_accessible(); if (!root) { Tcl_SetResult(interp, "Failed to initialize root accessible object", TCL_STATIC); return TCL_ERROR; } g_debug("TkAtkAccessibility_Init: Root accessible object created: %p (ref_count=%d)", root, G_OBJECT(root)->ref_count); /* Verify atk_get_root returns the correct object */ if (atk_get_root() != tk_root_accessible) { g_warning("TkAtkAccessibility_Init: atk_get_root() does not return tk_root_accessible %p", tk_root_accessible); } else { g_debug("TkAtkAccessibility_Init: atk_get_root() correctly returns tk_root_accessible %p", tk_root_accessible); } /* Initialize ATK bridge AFTER creating the root */ if (atk_bridge_adaptor_init(NULL, NULL) != 0) { Tcl_SetResult(interp, "Failed to initialize AT-SPI bridge", TCL_STATIC); g_object_unref(root); return TCL_ERROR; } g_debug("TkAtkAccessibility_Init: ATK bridge initialized"); /* Get main application window */ Tk_Window mainWin = Tk_MainWindow(interp); if (!mainWin) { Tcl_SetResult(interp, "No main window available", TCL_STATIC); g_object_unref(root); return TCL_ERROR; } const char *path = Tk_PathName(mainWin); if (!path) { Tcl_SetResult(interp, "Main window path is NULL", TCL_STATIC); g_object_unref(root); return TCL_ERROR; } /* Create main window accessible object */ AtkObject *main_acc = TkCreateAccessibleAtkObject_core(interp, mainWin, path); if (!main_acc) { Tcl_SetResult(interp, "Failed to create accessible object for main window", TCL_STATIC); g_object_unref(root); return TCL_ERROR; } g_debug("TkAtkAccessibility_Init: Main window accessible object created: %p", main_acc); RegisterToplevelWindow_core(interp, mainWin, main_acc); TkAtkAccessible_RegisterEventHandlers_core(mainWin, main_acc); /* Install GLib-Tk event loop integration */ InstallGtkEventLoop(); g_debug("TkAtkAccessibility_Init: GLib-Tk event loop installed"); /* Notify AT-SPI of hierarchy changes */ SignalData *signal_data = g_new(SignalData, 1); signal_data->obj = root; signal_data->signal_name = "children-changed"; signal_data->data = NULL; RunOnMainThread(ThreadSafe_EmitSignal, signal_data); g_debug("TkAtkAccessibility_Init: Emitted children-changed signal for root"); /* Flush the event queue to ensure AT-SPI processes signals */ g_main_context_iteration(NULL, TRUE); g_debug("TkAtkAccessibility_Init: Event queue flushed"); /* Register Tcl commands */ Tcl_CreateObjCommand(interp, "::tk::accessible::add_acc_object", TkAtkAccessibleObjCmd_core, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::emit_selection_change", EmitSelectionChanged_core, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::emit_focus_change", EmitFocusChanged_core, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::check_screenreader", IsScreenReaderRunning_core, NULL, NULL); g_debug("TkAtkAccessibility_Init: Tcl commands registered"); return TCL_OK; } #else /* No ATK found */ int TkAtkAccessibility_Init(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp, "::tk:de:accessible::add_acc_object", NULL, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::emit_selection_change", NULL, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::emit_focus_change", NULL, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::accessible::check_screenreader", NULL, NULL, NULL); return TCL_OK; } #endif /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |