Use GLib.MainLoop.new(None, False).quit() to terminate GLib.MainLoop.new(None, False).run() not work well, what is wrong?

Hi,

My problem:
I’m using Wnck to handle some single like window-closed to quit my app, but I stuck in the test code with a warning “invalid unclassed pointer in cast to ‘WnckClassGroup’”, sometime I got Segmentation fault due to this warning.

Test code:
Please note that this code is similar to the second example of Part II. Getting Started with libwnck: Libwnck Reference Manual. The different is that I quit the whole code via loop.quit().

def test_window_state_changed_using_gdk_simple():
    Gdk.init([])
    screen: Wnck.Screen = Wnck.Screen.get_default()
    screen.force_update()

    loop = GLib.MainLoop.new(None, False)

    h = []

    def do_window_state_changed(window_changed: Wnck.Window,
                                change_mask: Wnck.WindowState,
                                new_state: Wnck.WindowState):

        print('window title name -> ' + window_changed.get_name())
        print('window id -> ' + str(window_changed.get_xid()))
        h.append(window_changed.get_name())
        print('h -> ' + str(h))

        # Let the Gdk instance to go away
        loop.quit()

    window_found = False

    windows = screen.get_windows()
    for window in windows:
        if 'clock' in window.get_name().lower():
            window.connect('state-changed', do_window_state_changed)
            print('Found Clocks, window id -> ' + str(window.get_xid()) + ", connected state-changed")
            window_found = True
            break

    def do_window_closed(screen_window_closed_on: Wnck.Screen,
                         window_closed: Wnck.Window):
        print("window closed")
        print('window_closed id -> ' + str(window_closed.get_xid()))
        loop.quit()

    screen.connect('window-closed', do_window_closed)

    if window_found:
        # so = suppress_output.SuppressOutput(True, True)
        # with so.suppress_output():
        #     loop.run()

        loop.run()

        print("quit GLib.MainLoop()")
    else:
        print("quit, Clocks not launched")

    # loop.unref()

    time.sleep(1)
    print("done")


if __name__ == '__main__':
    test_window_state_changed_using_gdk_simple()

How to reproduce:

  1. Open Clocks (gnome-clocks)
  2. Run test code in a terminal
  3. Close Clocks manually
  4. You may see output below in the terminal
    /com/test/gui/gnome/gobject_introspection/gdk/glib_gdk_test.py:191: Warning: invalid unclassed pointer in cast to ‘WnckClassGroup’
    test_window_state_changed_using_gdk_simple()
    /com/test/gui/gnome/gobject_introspection/gdk/glib_gdk_test.py:191: Warning: g_hash_table_remove_internal: assertion ‘hash_table != NULL’ failed
    test_window_state_changed_using_gdk_simple()

4.1 Or not, often I got:
fish: Job 1, ‘python /mnt/xxx/co…’ terminated by signal SIGSEGV (Address boundary error)

Seems this is a blocking issue, I can not put this code in my code, unless find out what’s wrong with my code and how to write correct one. I’m new to Gtk/Glib BTW.

Any help welcome, I have tried my best to debug this kind of issue, but I failed, It’s difficult to find the cause and correct code.

I can not suppress them because it still could be terminated by signal SIGSEGV.

gdb info:
https://bpa.st/DTWQ

gdb info (top 20, in case of reaching expiry):

#0  g_type_check_instance_cast (type_instance=type_instance@entry=0x55e394329c40, iface_type=0x55e3942ca570 [None])
    at ../gobject/gtype.c:4115
#1  0x00007fbfd4022ec1 in window_weak_notify_cb (data=0x55e394329c40, where_the_window_was=0x55e394319a00)
    at ../libwnck/class-group.c:509
#2  0x00007fbfd5cbf6c7 in weak_refs_notify (data=0x55e39433d960) at ../gobject/gobject.c:2967
#3  0x00007fbfd5d585de in g_data_set_internal
    (datalist=0x55e394319a10, key_id=<optimized out>, new_data=<optimized out>, new_destroy_func=<optimized out>, dataset=0x0) at ../glib/gdataset.c:407
#4  0x00007fbfd5cc3a94 in g_object_unref (_object=<optimized out>) at ../gobject/gobject.c:3486
#5  g_object_unref (_object=0x55e394319a00) at ../gobject/gobject.c:3416
#6  0x00007fbfd5e9a9be in pygobject_dealloc ()
    at /usr/lib64/python3.9/site-packages/gi/_gi.cpython-39-x86_64-linux-gnu.so
#7  0x00007fbfe410344e in subtype_dealloc (self=<Window at remote 0x7fbfd405b4c0>)
    at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/typeobject.c:1337
#8  0x00007fbfe40e14aa in _Py_Dealloc (op=<optimized out>)
    at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/object.c:2203
#9  _Py_DECREF (op=<optimized out>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/object.h:430
#10 _Py_XDECREF (op=<optimized out>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/object.h:497
#11 list_dealloc (op=0x7fbfd49ec8c0) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/listobject.c:336
#12 0x00007fbfe40f3c28 in _Py_Dealloc (op=<optimized out>)
    at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/object.c:2209
#13 _Py_DECREF (op=<optimized out>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/object.h:430
#14 frame_dealloc
    (f=Frame 0x55e394124720, for file /mnt/xxx/xxxx/com/test/gui/gnome/gobject_introspection/gdk/glib_gdk_test.py, line 633, in test_window_state_changed_using_gdk (do_window_closed=<function at remote 0x7fbfd641fe50>)) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/frameobject.c:582
#15 0x00007fbfe40ea99a in _Py_Dealloc (op=<optimized out>)
    at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/object.c:2209
#16 _Py_DECREF (op=<optimized out>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/object.h:430
#17 _PyEval_EvalCode
    (tstate=<optimized out>, _co=<optimized out>, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, kwnames=0x0, kwargs=0x7fbfd66eb930, kwcount=<optimized out>, kwstep=1, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name='test_window_state_changed_using_gdk', qualname='test_window_state_changed_using_gdk') at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Python/ceval.c:4342
#18 0x00007fbfe40f845e in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Objects/call.c:396
#19 0x00007fbfe40eba5a in _PyObject_VectorcallTstate (kwnames=0x0, nargsf=<optimized out>, args=0x7fbfd66eb930, callable=<function at remote 0x7fbfd51d6a60>, tstate=0x55e393fa1b20) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/cpython/abstract.h:118
#20 PyObject_Vectorcall (kwnames=0x0, nargsf=<optimized out>, args=0x7fbfd66eb930, callable=<function at remote 0x7fbfd51d6a60>) at /usr/src/debug/python3.9-3.9.5-2.fc34.x86_64/Include/cpython/abstract.h:127

Similar issue:

libwnck is **not ** the right thing to use for controlling your own application windows. It is old plumbing for writing desktop components such as pagers or panels and only works on X11.

GtkWimdow has a ::close-request signal you can use to learn when windows are closed.

No, I’m not using wnck to controll my own app windows, I’m using it to controll other app’s.

I‘ll check it out. Thanks for your advice.

Why are you starting and stopping the main loop? That’s really not how things work.

Wnck is meant to be used in the same way a GTK application would work: you start the main loop, and you keep processing events.

The GtkWindow::close-request (or GtkWidget::delete-event, for GTK3) signals are only meant to be used for top level windows you create.

If you’re writing an X11-only tool to manipulate all top level windows from multiple processes that you don’t spawn yourself, then you have to use Wnck—though, to be fair, there’s really no reason why you should write something like that in 2021.

If you want to do some pattern matching on the windows during your session, I’d recommend you look at projects like Devil’s Pie.

In that case, libwnck makes some more sense, but it still restricts you to X11.

Under Wayland, manipulating windows is exclusively compositor functionality, so you’d have to look at a gnome-shell extension if you want things to work on Wayland.

1 Like

I’m not create windows myself, I only want to manipulate them, like moving a window to another workspace, restore their position and geometry and _NET_WM_STATE etc.

I really don’t need to start a loop and listen when something happens.

In a case,

  1. Set Clocks to sticky or above-all-apps
  2. I move Clocks to anotherworkspace via Wnck, and I find that it no longer is sticky or above-all-apps. This properties will be removed asynchrozed.

That why I want use a loop and listen when the window-state changed and I can restore window-state. And I don’t need to keep that loop running for a long time, once done what I want it just can go away.

Only works on X11 is find for me for the moment, I want to learn python and Gtk/gui anyway.

If a window is not created by me, I can not use this signals, right?

I have used devilspie2 to make a fullscreen window sticky, but I’m not familiar to lua. I can use python to do more complex things…

If it’s a learning exercise, you might learn more from writing a different sort of application than one that uses outdated tech like libwnck! (libwnck won’t teach you much about GTK)

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.