Tk Source Code

Check-in [ee4e1c53]
Login

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: ee4e1c5387a0b60da30aa5b5a10d03b7cc5b9accb67a9ffed6d54292f2825376
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
Unified Diff Ignore Whitespace Patch
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
312















































313
314
315
316
317
318
319
320
 *
 *----------------------------------------------------------------------
 */

/*
 * Functions to initialize and manage the parent Atk class and object instances.
 */
















































    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;







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







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
1453

1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484

1485



1486
1487



1488


1489
1490

1491
1492
1493

1494
1495
1496
1497

1498
1499
1500
1501
1502
1503
1504
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", root);

        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);

    /* Set application name. */
    SetNameData *name_data = g_new(SetNameData, 1);
    name_data->obj = obj;
    name_data->name = "Tk Application";
    RunOnMainThread(ThreadSafe_SetName, name_data);

    /* 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_hash_table_insert(tk_to_atk_map, NULL, obj);




    g_mutex_unlock(&root_accessible_mutex);



    g_debug("tk_create_root_accessible: Created and registered root %p", obj);



    /* Ensure AT-SPI is aware of the root. */

    SignalData *signal_data = g_new(SignalData, 1);
    signal_data->obj = obj;
    signal_data->signal_name = "children-changed";

    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. */







|
>













<
<
<
<
|
<

|








|

>

>
>
>


>
>
>
|
>
>
|
|
>



>




>







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
2022
2023
2024
2025
2026
2027
2028
2029

2030
2031
2032
2033
2034
2035
2036

2037
2038
2039
2040





2041
2042
2043
2044
2045
2046


2047









2048
2049
2050

2051
2052

2053
2054
2055
2056
2057

2058
2059
2060
2061
2062
2063

2064
2065
2066
2067
2068
2069
2070

2071
2072

2073
2074
2075
2076
2077
2078

2079
2080
2081
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
 *
 *----------------------------------------------------------------------
 */

#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);

    
    /* 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;
    }


    /* Initialize GObject type system (noop since GLib 2.36). */
    g_type_init();






    /* Create the root accessible object first. */
    AtkObject *root = tk_create_root_accessible();
    if (!root) {
        Tcl_SetResult(interp, "Failed to initialize root accessible object", TCL_STATIC);
        return TCL_ERROR;
    }












    /* 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);

        return TCL_ERROR;
    }


    /* Get main application window. */
    Tk_Window mainWin = Tk_MainWindow(interp);
    if (!mainWin) {
        Tcl_SetResult(interp, "No main window available", TCL_STATIC);

        return TCL_ERROR;
    }

    const char *path = Tk_PathName(mainWin);
    if (!path) {
        Tcl_SetResult(interp, "Main window path is NULL", TCL_STATIC);

        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);

        return TCL_ERROR;
    }


    RegisterToplevelWindow_core(interp, mainWin, main_acc);
    TkAtkAccessible_RegisterEventHandlers_core(mainWin, main_acc);

    /* Install GLib-Tk event loop integration. */
    InstallGtkEventLoop();


    /* Notify AT-SPI of hierarchy changes. */
    SignalData *signal_data = g_new(SignalData, 1);
    signal_data->obj = root;
    signal_data->signal_name = "children-changed";

    RunOnMainThread(ThreadSafe_EmitSignal, signal_data);



    g_main_context_iteration(NULL, TRUE); /* Flush. */


    /* 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);


    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:
 */







|




|


>
|
|





>

|


>
>
>
>
>
|





>
>

>
>
>
>
>
>
>
>
>
|


>


>

|



>






>



|



>


>




|

>

|



>

>

>
|
>

|








>




|









<








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:
 */