Accessibility problem with custom GtkWidget



Hello,

I'm an accessibility newbie asking for some help (a hint would be enough) with a custom GtkWidget. As I planned to add some Atspi functionality I found out that my widget is "disturbing" AtspiEventListener. When there is an AtspiEventListener and I open a window with my widget and close it again, the listener emits a couple of "g_object_unref: assertion 'G_IS_OBJECT (object)' failed" messages.

So obviously my widget is doing something wrong or probably doesn't do something it should do. It's a composite widget: a GtkScrolledWindow that is showing a couple of GtkDrawingAreas over each other in a GtkOverlay. It looks like this: https://gkarsay.github.io/parlatype/reference/PtWaveviewer.html

I'm not asking you to have a look at the widget code itself, just some general advice what a custom widget should do. Have you seen something like this before?

Just to clarify, I didn't do anything yet to improve accessibility. I thought if the subwidgets are accessible, then the whole custom widget is accessible.

I wrote a test case with a listener. It's just listening as long as the window is open:

--------- test.c -----------

/* Compile:
   gcc -g -o test test.c `pkg-config --libs --cflags gtk+-3.0 atspi-2`
*/


#include <gtk/gtk.h>
#include <atspi/atspi.h>

static void
on_event_cb (AtspiEvent *event,
             void       *user_data)
{
        /* nothing */
}

static void
app_activate (GApplication *app,
              gpointer      user_data)
{
        AtspiEventListener *listener;
        GtkWidget          *window;

listener = atspi_event_listener_new ((AtspiEventListenerCB) on_event_cb, NULL, NULL); atspi_event_listener_register (listener, "object:state-changed:focused", NULL);

        window = gtk_application_window_new (GTK_APPLICATION (app));
        gtk_window_present (GTK_WINDOW (window));
}

int main(int argc, gchar **argv)
{
        GtkApplication *app;
        gint            status;

        app = gtk_application_new ("org.example.test", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
        status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);

        return status;
}

----- test.c end ---------------

When I run the test (in Debian stable and unstable), open my widget (Parlatype) and close it again, I get this from the test program:

(gdb) bt full
#0 0x00007ffff56de261 in _g_log_abort (breakpoint=breakpoint@entry=1) at ././glib/gmessages.c:509
        debugger_present = 1
#1 0x00007ffff56df66d in g_logv (log_domain=0x7ffff5e5e9b6 "GLib-GObject", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fffffffdba0) at ././glib/gmessages.c:1318
        domain = 0x0
        data = 0x0
        depth = 1
        log_func = 0x7ffff56df1f0 <g_log_default_handler>
        domain_fatal_mask = <optimized out>
        masquerade_fatal = 0
        test_level = 10
        was_fatal = <optimized out>
        was_recursion = <optimized out>
msg = 0x555555a4bdb0 "g_object_unref: assertion 'G_IS_OBJECT (object)' failed" msg_alloc = 0x555555a4bdb0 "g_object_unref: assertion 'G_IS_OBJECT (object)' failed"
        i = 3
#2 0x00007ffff56df7cf in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ././glib/gmessages.c:1359 args = {{gp_offset = 40, fp_offset = 48, overflow_arg_area = 0x7fffffffdc80, reg_save_area = 0x7fffffffdbc0}} #3 0x00007ffff56aca9b in g_ptr_array_foreach (array=0x5555558f8100, func=0x7ffff5e37ae0 <g_object_unref>, user_data=0x0) at ././glib/garray.c:1502
        i = 2
#4 0x00007ffff56acb30 in ptr_array_free (array=0x5555558f8100, flags=FREE_SEGMENT) at ././glib/garray.c:1088
        rarray = 0x5555558f8100
        segment = <optimized out>
#5 0x00007ffff56acba9 in g_ptr_array_free (array=<optimized out>, free_segment=free_segment@entry=1) at ././glib/garray.c:1075
        rarray = <optimized out>
        flags = <optimized out>
        __func__ = "g_ptr_array_free"
#6 0x00007ffff5c02395 in atspi_accessible_dispose (object=0x5555558201a0 [AtspiAccessible]) at atspi-accessible.c:164
        accessible = 0x5555558201a0 [AtspiAccessible]
e = {type = 0x7ffff5c14aa2 "object:state-changed:defunct", source = 0x5555558201a0 [AtspiAccessible], detail1 = 1, detail2 = 0, any_data = {g_type = 24, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}}
        parent = <optimized out>
        i = -1
#7 0x00007ffff5e39648 in g_object_run_dispose (object=0x5555558201a0 [AtspiAccessible]) at ././gobject/gobject.c:1084
        __func__ = "g_object_run_dispose"
#8 0x00007ffff5c0b3bc in handle_remove_accessible (bus=<optimized out>, user_data=<optimized out>, message=<optimized out>) at atspi-misc.c:357
        app = 0x555555a2a250 [AtspiApplication]
iter = {dummy1 = 0x5555558dd840, dummy2 = 0x7fff00600000, dummy3 = 108, dummy4 = 0, dummy5 = 1435359304, dummy6 = 21845, dummy7 = 117, dummy8 = 0, dummy9 = 1435359376, dummy10 = 21845, dummy11 = 0, pad1 = 0, pad2 = 0x7ffff5befea0, pad3 = 0x0}
        a = 0x5555558201a0 [AtspiAccessible]
        sender = 0x55555585d934 ":1.31"
        path = 0x55555585d940 "/org/a11y/atspi/accessible/5"
iter_struct = {dummy1 = 0x5555558dd840, dummy2 = 0x7fff00600000, dummy3 = 108, dummy4 = 0, dummy5 = 1435359304, dummy6 = 21845, dummy7 = 119, dummy8 = 0, dummy9 = 1435359376, dummy10 = 21845, dummy11 = 10, pad1 = 0, pad2 = 0x7ffff5befe20, pad3 = 0x0}
        signature = <optimized out>
        type = <optimized out>
        interface = <optimized out>
        closure = 0x555555964330
        in_process_deferred_messages = 1
#9 0x00007ffff5c0b3bc in process_deferred_message (closure=0x555555964330) at atspi-misc.c:753
        type = <optimized out>
        interface = <optimized out>
        closure = 0x555555964330
        in_process_deferred_messages = 1
#10 0x00007ffff5c0b3bc in process_deferred_messages () at atspi-misc.c:774
        closure = 0x555555964330
        in_process_deferred_messages = 1
#11 0x00007ffff5c0b599 in process_deferred_messages () at atspi-misc.c:785
        in_process_deferred_messages = 1
        in_process_deferred_messages = 1
#12 0x00007ffff5c0b599 in process_deferred_messages_callback (data=<optimized out>) at atspi-misc.c:786 #13 0x00007ffff56d86aa in g_main_dispatch (context=0x55555576e070) at ././glib/gmain.c:3203
        dispatch = 0x7ffff56d50d0 <g_idle_dispatch>
        prev_source = 0x0
        was_in_call = 0
        user_data = 0x0
        callback = 0x7ffff5c0b580 <process_deferred_messages_callback>
        cb_funcs = <optimized out>
        cb_data = 0x555555903080
        need_destroy = <optimized out>
        source = 0x555555879730
        current = 0x555555780320
        i = 0
#14 0x00007ffff56d86aa in g_main_context_dispatch (context=context@entry=0x55555576e070) at ././glib/gmain.c:3856 #15 0x00007ffff56d8a60 in g_main_context_iterate (context=context@entry=0x55555576e070, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ././glib/gmain.c:3929
        max_priority = 200
        timeout = 0
        some_ready = 1
        nfds = 4
        allocated_nfds = 4
        fds = <optimized out>
#16 0x00007ffff56d8b0c in g_main_context_iteration (context=context@entry=0x55555576e070, may_block=may_block@entry=1) at ././glib/gmain.c:3990
        retval = <optimized out>
#17 0x00007ffff611572d in g_application_run (application=0x55555576c1a0 [GtkApplication], argc=1, argv=0x7fffffffe0d8) at ././gio/gapplication.c:2381
        arguments = 0x555555762420
        status = 0
        context = 0x55555576e070
        acquired_context = <optimized out>
        __func__ = "g_application_run"
#18 0x0000555555554d50 in main (argc=1, argv=0x7fffffffe0d8) at test.c:52
        app = 0x55555576c1a0 [GtkApplication]
        status = 32767

--- backtrace end ----

Any advice is welcome. Is there some online How-do-I for improving accessibility? I found only the API reference. It tells me how to do something, but first I have to know what to do.

Thank you!
Gabor


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]