Tk Source Code

Check-in [2cb94468]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Remove unneeded notifications
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tka11y
Files: files | file ages | folders
SHA3-256: 2cb944683f0ac757b8623158dcebe121d87647c2745c83a9f7ddecf7525e2e58
User & Date: kevin_walzer 2025-07-27 01:11:30.116
Context
2025-07-27
01:32
Remove compiler warnings check-in: cb8f83f4 user: kevin_walzer tags: tka11y
01:11
Remove unneeded notifications check-in: 2cb94468 user: kevin_walzer tags: tka11y
2025-07-26
22:35
Remove compiler errors check-in: 921c37ff user: kevin_walzer tags: tka11y
Changes
Unified Diff Ignore Whitespace Patch
Changes to unix/tkUnixAccessibility.c.
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
    }

    /* Special case for toplevel windows. */
    if (Tk_IsTopLevel(win)) {
	role = ATK_ROLE_WINDOW;
    }
    
    /* Notify system of role attribute. */
    g_object_notify(G_OBJECT(obj), "accessible-role");
    return role;
}

static AtkRole tk_get_role(AtkObject *obj)
{
    TkAtkAccessible *acc = (TkAtkAccessible *)obj;
    Tk_Window win = acc->tkwin;







<
<







282
283
284
285
286
287
288


289
290
291
292
293
294
295
    }

    /* Special case for toplevel windows. */
    if (Tk_IsTopLevel(win)) {
	role = ATK_ROLE_WINDOW;
    }
    


    return role;
}

static AtkRole tk_get_role(AtkObject *obj)
{
    TkAtkAccessible *acc = (TkAtkAccessible *)obj;
    Tk_Window win = acc->tkwin;
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    if (!acc) return; 

    if (obj == tk_root_accessible) {
	/* Free old cached name, store new one. */
        g_free(acc->cached_name);
        acc->cached_name = g_strdup(name); 
    }
    atk_object_set_name(acc, name);
    g_object_notify(G_OBJECT(acc), "accessible-name");
    g_signal_emit_by_name(acc, "name-changed");
}


static const gchar *tk_get_description(AtkObject *obj)
{
    TkAtkAccessible *acc = (TkAtkAccessible *)obj;

    if (!acc || !acc->tkwin) return NULL;

    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(TkAccessibilityObject, (char *)acc->tkwin);
    if (!hPtr) return NULL;

    Tcl_HashTable *AccessibleAttributes = (Tcl_HashTable *)Tcl_GetHashValue(hPtr);
    if (!AccessibleAttributes) return NULL;

    Tcl_HashEntry *hPtr2 = Tcl_FindHashEntry(AccessibleAttributes, "description");
    if (!hPtr2) return NULL;

    const char *result = Tcl_GetString(Tcl_GetHashValue(hPtr2));
    if (result) {
        g_object_notify(G_OBJECT(obj), "accessible-description");
        g_signal_emit_by_name(obj, "description-changed");
        return g_strdup(result); /* ATK expects a newly allocated string. */
    }
    return NULL;
}

/*
 * Functions to map accessible value to Atk using







|
<
<




















<
<







398
399
400
401
402
403
404
405


406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425


426
427
428
429
430
431
432
    if (!acc) return; 

    if (obj == tk_root_accessible) {
	/* Free old cached name, store new one. */
        g_free(acc->cached_name);
        acc->cached_name = g_strdup(name); 
    }
    atk_object_set_name(obj, name);


}


static const gchar *tk_get_description(AtkObject *obj)
{
    TkAtkAccessible *acc = (TkAtkAccessible *)obj;

    if (!acc || !acc->tkwin) return NULL;

    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(TkAccessibilityObject, (char *)acc->tkwin);
    if (!hPtr) return NULL;

    Tcl_HashTable *AccessibleAttributes = (Tcl_HashTable *)Tcl_GetHashValue(hPtr);
    if (!AccessibleAttributes) return NULL;

    Tcl_HashEntry *hPtr2 = Tcl_FindHashEntry(AccessibleAttributes, "description");
    if (!hPtr2) return NULL;

    const char *result = Tcl_GetString(Tcl_GetHashValue(hPtr2));
    if (result) {


        return g_strdup(result); /* ATK expects a newly allocated string. */
    }
    return NULL;
}

/*
 * Functions to map accessible value to Atk using
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
        g_value_set_string(value, "");
        return;
    }

    char *result = Tcl_GetString(Tcl_GetHashValue(hPtr2));
    g_value_init(value, G_TYPE_STRING);
    g_value_set_string(value, result ? result : "");
    g_object_notify(G_OBJECT(atkObj), "accessible-value");
}

static void tk_atk_value_interface_init(AtkValueIface *iface)
{
    iface->get_current_value = tk_get_current_value;
}








<







468
469
470
471
472
473
474

475
476
477
478
479
480
481
        g_value_set_string(value, "");
        return;
    }

    char *result = Tcl_GetString(Tcl_GetHashValue(hPtr2));
    g_value_init(value, G_TYPE_STRING);
    g_value_set_string(value, result ? result : "");

}

static void tk_atk_value_interface_init(AtkValueIface *iface)
{
    iface->get_current_value = tk_get_current_value;
}

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
    /* Ensure root exists. */
    if (!tk_root_accessible) {
        tk_root_accessible = tk_util_get_root();
    }

    /* Set proper parent-child relationship. */
    atk_object_set_parent(accessible, tk_root_accessible);
    g_object_notify(G_OBJECT(accessible), "accessible-parent");

    /* 
     * Add to toplevel list if not already present.
     * The list now holds a non-owning reference. 
     * Ownership is with tk_to_atk_map. 
     */
    if (!g_list_find(toplevel_accessible_objects, accessible)) {
        toplevel_accessible_objects = g_list_append(toplevel_accessible_objects, accessible);

	/* 
	 * Critical: Emit children-changed signal for AT-SPI update.
	 * The index should be the position where it was added.
	 */
        int index = g_list_length(toplevel_accessible_objects) - 1;
        g_signal_emit_by_name(tk_root_accessible, "children-changed::add", index, accessible);
    }

    /* Explicitly set and notify accessible name */
    const gchar *name = tk_get_name(accessible); 
    if (name) {
        tk_set_name(accessible, name);
        g_object_notify(G_OBJECT(accessible), "accessible-name");
        g_signal_emit_by_name(accessible, "name-changed");
        g_free((gpointer)name); /* Free the string returned by tk_get_name. */
    }

    /* Register child widgets recursively. */
    RegisterChildWidgets(interp, tkwin, accessible);
}








<














|






<
<







636
637
638
639
640
641
642

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663


664
665
666
667
668
669
670
    /* Ensure root exists. */
    if (!tk_root_accessible) {
        tk_root_accessible = tk_util_get_root();
    }

    /* Set proper parent-child relationship. */
    atk_object_set_parent(accessible, tk_root_accessible);


    /* 
     * Add to toplevel list if not already present.
     * The list now holds a non-owning reference. 
     * Ownership is with tk_to_atk_map. 
     */
    if (!g_list_find(toplevel_accessible_objects, accessible)) {
        toplevel_accessible_objects = g_list_append(toplevel_accessible_objects, accessible);

	/* 
	 * Critical: Emit children-changed signal for AT-SPI update.
	 * The index should be the position where it was added.
	 */
        int index = g_list_length(toplevel_accessible_objects) - 1;
        g_signal_emit_by_name((AtkObject*)tk_root_accessible, "children-changed::add", index, accessible);
    }

    /* Explicitly set and notify accessible name */
    const gchar *name = tk_get_name(accessible); 
    if (name) {
        tk_set_name(accessible, name);


        g_free((gpointer)name); /* Free the string returned by tk_get_name. */
    }

    /* Register child widgets recursively. */
    RegisterChildWidgets(interp, tkwin, accessible);
}

702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
            TkAtkAccessible_RegisterEventHandlers(child, (TkAtkAccessible *)child_obj);
        }

        /* Ensure proper parent relationship. */
        AtkObject *current_parent = atk_object_get_parent(child_obj);
        if (current_parent != parent_obj) {
	    /* 
             * If the child was previously parented to something else or unparented,
             * emit a remove signal from the old parent first if known.
	     * For simplicity, we'll just set the parent and emit 'add' for the new parent.
	     */
            atk_object_set_parent(child_obj, parent_obj);
	    g_object_notify(G_OBJECT(child_obj), "accessible-parent");
            g_signal_emit_by_name(parent_obj, "children-changed::add", index, child_obj);
        }

        /* Set the name for the child object. */
        const gchar *child_name = tk_get_name(child_obj);
        if (child_name) {
            tk_set_name(child_obj, child_name);
            g_object_notify(G_OBJECT(child_obj), "accessible-name");
            g_signal_emit_by_name(child_obj, "name-changed");
            g_free((gpointer)child_name);
        }

        /* Recursively register children. */
        RegisterChildWidgets(interp, child, child_obj);
        index++;
    }







|
|



<







<
<







692
693
694
695
696
697
698
699
700
701
702
703

704
705
706
707
708
709
710


711
712
713
714
715
716
717
            TkAtkAccessible_RegisterEventHandlers(child, (TkAtkAccessible *)child_obj);
        }

        /* Ensure proper parent relationship. */
        AtkObject *current_parent = atk_object_get_parent(child_obj);
        if (current_parent != parent_obj) {
	    /* 
         * If the child was previously parented to something else or unparented,
         * emit a remove signal from the old parent first if known.
	     * For simplicity, we'll just set the parent and emit 'add' for the new parent.
	     */
            atk_object_set_parent(child_obj, parent_obj);

            g_signal_emit_by_name(parent_obj, "children-changed::add", index, child_obj);
        }

        /* Set the name for the child object. */
        const gchar *child_name = tk_get_name(child_obj);
        if (child_name) {
            tk_set_name(child_obj, child_name);


            g_free((gpointer)child_name);
        }

        /* Recursively register children. */
        RegisterChildWidgets(interp, child, child_obj);
        index++;
    }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
{
    if (!tk_root_accessible) {
        TkAtkAccessible *acc = g_object_new(TK_ATK_TYPE_ACCESSIBLE, NULL);
        tk_root_accessible = ATK_OBJECT(acc);
        atk_object_initialize(tk_root_accessible, NULL);

        /* Set proper application name. */
	atk_object_set_role(tk_root_accessible, ATK_ROLE_APPLICATION);
        g_object_notify(G_OBJECT(tk_root_accessible), "accessible-role");

        /* Set an initial name for the root, can be updated later. */
        tk_set_name(tk_root_accessible, "Tk Application");
        g_object_notify(G_OBJECT(tk_root_accessible), "accessible-name");
        g_signal_emit_by_name(tk_root_accessible, "name-changed");
    }

    return tk_root_accessible;
}

/* Core function linking Tk objects to the Atk root object and at-spi. */
AtkObject *atk_get_root(void) {







|
<



<
<







733
734
735
736
737
738
739
740

741
742
743


744
745
746
747
748
749
750
{
    if (!tk_root_accessible) {
        TkAtkAccessible *acc = g_object_new(TK_ATK_TYPE_ACCESSIBLE, NULL);
        tk_root_accessible = ATK_OBJECT(acc);
        atk_object_initialize(tk_root_accessible, NULL);

        /* Set proper application name. */
		atk_object_set_role(tk_root_accessible, ATK_ROLE_APPLICATION);


        /* Set an initial name for the root, can be updated later. */
        tk_set_name(tk_root_accessible, "Tk Application");


    }

    return tk_root_accessible;
}

/* Core function linking Tk objects to the Atk root object and at-spi. */
AtkObject *atk_get_root(void) {
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
    acc->interp = interp;
    acc->tkwin = tkwin;
    acc->path = g_strdup(path); 

    /* Set initial accessibility properties (role and name). */
    AtkObject *obj = ATK_OBJECT(acc);
    atk_object_set_role(obj, GetAtkRoleForWidget(tkwin));
    g_object_notify(G_OBJECT(obj), "accessible-role");

    /* Initial name setting for the object. */
    const gchar *name = tk_get_name(obj);
    if (name) {
        tk_set_name(obj, name);
        g_object_notify(G_OBJECT(obj), "accessible-name");
        g_signal_emit_by_name(obj, "name-changed");
        g_free((gpointer)name); /* Free the string returned by tk_get_name. */
    }

    /* Set up parent-child relationships for the widget. */
    if (tkwin) {
        Tk_Window parent_tkwin = Tk_Parent(tkwin);
        AtkObject *parent_obj = NULL;

        if (parent_tkwin) {
            parent_obj = GetAtkObjectForTkWindow(parent_tkwin);
        } else {
            /* If no Tk parent, it's a toplevel, parent it to the root accessible. */
            parent_obj = tk_root_accessible;
        }

        if (parent_obj) {
            atk_object_set_parent(obj, parent_obj);
            g_object_notify(G_OBJECT(obj), "accessible-parent");
	    /* 
	     * Emit children-changed signal for the parent to update AT-SPI.
	     * The index here is an approximation; a more precise index would require
	     * knowing the exact position in the parent's child list.
	     */
            g_signal_emit_by_name(parent_obj, "children-changed::add", -1, obj);
        }







<





<
<

















<







764
765
766
767
768
769
770

771
772
773
774
775


776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792

793
794
795
796
797
798
799
    acc->interp = interp;
    acc->tkwin = tkwin;
    acc->path = g_strdup(path); 

    /* Set initial accessibility properties (role and name). */
    AtkObject *obj = ATK_OBJECT(acc);
    atk_object_set_role(obj, GetAtkRoleForWidget(tkwin));


    /* Initial name setting for the object. */
    const gchar *name = tk_get_name(obj);
    if (name) {
        tk_set_name(obj, name);


        g_free((gpointer)name); /* Free the string returned by tk_get_name. */
    }

    /* Set up parent-child relationships for the widget. */
    if (tkwin) {
        Tk_Window parent_tkwin = Tk_Parent(tkwin);
        AtkObject *parent_obj = NULL;

        if (parent_tkwin) {
            parent_obj = GetAtkObjectForTkWindow(parent_tkwin);
        } else {
            /* If no Tk parent, it's a toplevel, parent it to the root accessible. */
            parent_obj = tk_root_accessible;
        }

        if (parent_obj) {
            atk_object_set_parent(obj, parent_obj);

	    /* 
	     * Emit children-changed signal for the parent to update AT-SPI.
	     * The index here is an approximation; a more precise index would require
	     * knowing the exact position in the parent's child list.
	     */
            g_signal_emit_by_name(parent_obj, "children-changed::add", -1, obj);
        }
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871

872
873
874
875
876
877
878
    }

    if (!g_main_context_acquire(context)) {
        g_warning("InstallGtkEventLoop: Failed to acquire GLib main context");
        return;
    }

    Tcl_CreateTimerHandler(10, GtkEventLoop, context);
    g_debug("InstallGtkEventLoop: Installed GLib event loop");
}

static void GtkEventLoop(ClientData clientData) 
{
    GMainContext *context = (GMainContext *)clientData;
    if (!context) {
        g_warning("GtkEventLoop: Context is NULL");
        return;
    }

    /* Process all pending events.*/
    int iterations = 0;
    while (g_main_context_pending(context) && iterations < 100) {
        if (!g_main_context_iteration(context, FALSE)) {
            break;
        }
        iterations++;
    }
    if (iterations >= 100) {
        g_warning("GtkEventLoop: Excessive iterations (%d), possible event loop issue", iterations);
    }

    /* Reschedule the event loop. */
    Tcl_CreateTimerHandler(10, GtkEventLoop, clientData);
    g_debug("GtkEventLoop: Processed %d iterations", iterations);
}


/*
 * Functions to map Tk window to its corresponding Atk object.
 */

void InitAtkTkMapping(void)
{







|






|
<
<
|
|
<

|
|
<
<


<
<
|
<
|
|
<

>







817
818
819
820
821
822
823
824
825
826
827
828
829
830
831


832
833

834
835
836


837
838


839

840
841

842
843
844
845
846
847
848
849
850
    }

    if (!g_main_context_acquire(context)) {
        g_warning("InstallGtkEventLoop: Failed to acquire GLib main context");
        return;
    }

    Tcl_CreateTimerHandler(50, GtkEventLoop, context);
    g_debug("InstallGtkEventLoop: Installed GLib event loop");
}

static void GtkEventLoop(ClientData clientData) 
{
    GMainContext *context = (GMainContext *)clientData;
    if (!context) return;



/* Process GLib events immediately. */

    int iterations = 0;
    while (g_main_context_pending(context) && iterations < 25) {
        if (!g_main_context_iteration(context, FALSE)) break;


        iterations++;
    }




     /* Reschedule the event loop. */
    Tcl_CreateTimerHandler(50, GtkEventLoop, clientData);

}


/*
 * Functions to map Tk window to its corresponding Atk object.
 */

void InitAtkTkMapping(void)
{
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
        return TCL_ERROR;
    }

    AtkRole role = atk_object_get_role(acc);

    GValue gval = G_VALUE_INIT;
    tk_get_current_value(ATK_VALUE(acc), &gval);
    g_object_notify(G_OBJECT(acc), "accessible-value");
    g_signal_emit_by_name(G_OBJECT(acc), "value-changed", &gval);
    g_value_unset(&gval); /* Unset the GValue to free any allocated memory. */

    if (role == ATK_ROLE_TEXT || role == ATK_ROLE_ENTRY) {
        g_signal_emit_by_name(acc, "text-selection-changed");
    }
   
    return TCL_OK;







<
|







918
919
920
921
922
923
924

925
926
927
928
929
930
931
932
        return TCL_ERROR;
    }

    AtkRole role = atk_object_get_role(acc);

    GValue gval = G_VALUE_INIT;
    tk_get_current_value(ATK_VALUE(acc), &gval);

    g_signal_emit_by_name(acc, "value-changed", &gval);
    g_value_unset(&gval); /* Unset the GValue to free any allocated memory. */

    if (role == ATK_ROLE_TEXT || role == ATK_ROLE_ENTRY) {
        g_signal_emit_by_name(acc, "text-selection-changed");
    }
   
    return TCL_OK;
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
    AtkObject *acc = GetAtkObjectForTkWindow(path_tkwin);
    if (!acc) {
	Tcl_SetResult(ip, "No accessible object for window", TCL_STATIC);
	return TCL_ERROR;
    }

    /* Emit focus-event with TRUE to indicate focus gained. */
    g_signal_emit_by_name(G_OBJECT(acc), "focus-event", TRUE);
    g_signal_emit_by_name(G_OBJECT(acc), "state-change", "focused", TRUE);

    return TCL_OK;
}


/*
 *----------------------------------------------------------------------







|
|







966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
    AtkObject *acc = GetAtkObjectForTkWindow(path_tkwin);
    if (!acc) {
	Tcl_SetResult(ip, "No accessible object for window", TCL_STATIC);
	return TCL_ERROR;
    }

    /* Emit focus-event with TRUE to indicate focus gained. */
    g_signal_emit_by_name(acc, "focus-event", TRUE);
    g_signal_emit_by_name(acc, "state-change", "focused", TRUE);

    return TCL_OK;
}


/*
 *----------------------------------------------------------------------
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150

    AtkObject *atk_obj = (AtkObject*) tkAccessible;
    if (atk_obj) {
	/* Get the current name and then set it to trigger notification. */
	const gchar *name = tk_get_name(atk_obj);
	if (name) {
	    tk_set_name(atk_obj, name);
	    g_object_notify(G_OBJECT(atk_obj), "accessible-name");
	    g_signal_emit_by_name(atk_obj, "name-changed");
	    g_free((gpointer)name); /* Free the string returned by tk_get_name. */
	}
    }
}


/*







<
<







1106
1107
1108
1109
1110
1111
1112


1113
1114
1115
1116
1117
1118
1119

    AtkObject *atk_obj = (AtkObject*) tkAccessible;
    if (atk_obj) {
	/* Get the current name and then set it to trigger notification. */
	const gchar *name = tk_get_name(atk_obj);
	if (name) {
	    tk_set_name(atk_obj, name);


	    g_free((gpointer)name); /* Free the string returned by tk_get_name. */
	}
    }
}


/*
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256

    /* Create and configure root object. */
    tk_root_accessible = tk_util_get_root();
    if (tk_root_accessible) {
	const gchar *name = tk_get_name(tk_root_accessible);
	if (name) {
	    tk_set_name(tk_root_accessible, name); /* Set the name and notify. */
	    g_object_notify(G_OBJECT(tk_root_accessible), "accessible-name");
	    g_signal_emit_by_name(tk_root_accessible, "name-changed");
	    g_free((gpointer)name); /* Free the string returned by tk_get_name. */
	}
    }

    /* Initialize AT-SPI bridge. */
    if (atk_bridge_adaptor_init(NULL, NULL) != 0) {
	g_warning("Failed to initialize AT-SPI bridge\n");







<
<







1210
1211
1212
1213
1214
1215
1216


1217
1218
1219
1220
1221
1222
1223

    /* Create and configure root object. */
    tk_root_accessible = tk_util_get_root();
    if (tk_root_accessible) {
	const gchar *name = tk_get_name(tk_root_accessible);
	if (name) {
	    tk_set_name(tk_root_accessible, name); /* Set the name and notify. */


	    g_free((gpointer)name); /* Free the string returned by tk_get_name. */
	}
    }

    /* Initialize AT-SPI bridge. */
    if (atk_bridge_adaptor_init(NULL, NULL) != 0) {
	g_warning("Failed to initialize AT-SPI bridge\n");
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
			 EmitFocusChanged, NULL, NULL);
    Tcl_CreateObjCommand(interp, "::tk::accessible::check_screenreader",
			 IsScreenReaderRunning, NULL, NULL);

    /* 
     * Force initial hierarchy update. 
     */
    g_signal_emit_by_name(tk_root_accessible, "children-changed", 0, NULL);

    return TCL_OK;
}

#else
/* No Atk found. */
int TkAtkAccessibility_Init(Tcl_Interp *interp)







|







1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
			 EmitFocusChanged, NULL, NULL);
    Tcl_CreateObjCommand(interp, "::tk::accessible::check_screenreader",
			 IsScreenReaderRunning, NULL, NULL);

    /* 
     * Force initial hierarchy update. 
     */
    g_signal_emit_by_name((AtkObject*)tk_root_accessible, "children-changed", 0, NULL);

    return TCL_OK;
}

#else
/* No Atk found. */
int TkAtkAccessibility_Init(Tcl_Interp *interp)