Undo doesn't emit `notified_changed` signal in a GTK/Python application
07:30 01 Feb 2026

I am trying to develop a PyGObject application but experiencing a strange behavior. I’ve created a demo for you to reproduce it. This is the code:

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio

app = Gtk.Application()
window = None
text_view = None
title = "Test"

def on_quit(action, _):
    app.quit()

def on_save_file(action, _):
    text_view.get_buffer().set_modified(False)

def create_action(target, name, handler):
    action = Gio.SimpleAction(name=name)
    action.connect("activate", handler)
    target.add_action(action)

def add_actions(app, window):
    create_action(app, "quit", on_quit)
    create_action(window, "save_file", on_save_file)

def set_accels_for_actions(app):
    app.set_accels_for_action("win.save_file", ["s"])
    app.set_accels_for_action("app.quit", ["q"])

def on_modified_changed(buffer):
    modified = buffer.get_modified()
    print("Modified:", modified)
    if modified:
        window.set_title(f"{title}*")
    else:
        window.set_title(title)

def on_activate_app(app):
    global window, text_view
    window = Gtk.ApplicationWindow(application=app)

    text_view = Gtk.TextView()
    text_view.get_buffer().connect("modified_changed", on_modified_changed)

    window.set_child(text_view)
    window.present()
    add_actions(app, window)
    set_accels_for_actions(app)

app.connect("activate", on_activate_app)
app.run()

You can quit from app using "Ctrl+q" and save the content with "Ctrl+s". Just do this:

* Write "a".

* Delete it with "Backspace".

* Write "b".

* Press "Ctrl-s" and save it. It is not a real save, just calls `buffer.set_modified(False)`. You can follow the `modified` flag value in the console.

* Delete it with "Backspace".

* Write "c".

* Now it is in modified state. You can follow it from the title. The title is updated whenever the `modified_changed` signal is triggered.

* Undo with "Ctrl-z" twice. As expected, it is now in the clean state.

* Undo one more time with "Ctrl-z". I think the expected thing is the dirty state again. But it is in the clear state!

Am I missing something or is it weird? BTW, sorry if the code is a mess. Original code follows best practices but this one is simpler.

python textview gtk undo pygobject