2

I want to display a button in a notification with pygobject. This button should call a callback when clicked, but it doesn't, and I don't understand why.

Here is my code :

from gi.repository import Notify, Gtk

class Test:
    def __init__(self):
        Notify.init('example')
        self.notif()

        Gtk.main()

    def notif(self):
        notif = Notify.Notification.new('Title', 'something','dialog-information')

        notif.add_action('display', 'Button', self.callback, None)
        notif.show()

    def callback(self, notif_object, action_name, users_data):
        print("Work!")
        Gtk.main_quit()

Test()

When I click on the button "Button", nothing happens and the callback is not called. What is the problem ?

After some tries, I found that when I put Gtk.main() immediately after notif.show(), the callback work. But I can't use this solution since it implies that I can't show other notifications later.

Richard Fearn
  • 25,073
  • 7
  • 56
  • 55
arthropode
  • 1,361
  • 2
  • 12
  • 19

2 Answers2

3

You need to hold reference to your notification object until the callback is called:

from gi.repository import Gtk, Notify


class Window(Gtk.Window):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        Notify.init('Test')
        self.notification = None

        self.set_border_width(5)

        self.button = Gtk.Button('Test')

        self.box = Gtk.Box()
        self.box.pack_start(self.button, True, True, 0)
        self.add(self.box)

        self.button.connect('clicked', self.on_button)
        self.connect('delete-event', Gtk.main_quit)
        self.show_all()

    def on_button(self, button):
        if self.notification:
            self.notification.close()
        self.notification = Notify.Notification.new('Test')
        self.notification.add_action('clicked', 'Action', self.callback)
        self.notification.show()

    def callback(self, notification, action_name):
        print(action_name)

win = Window()
Gtk.main()

If you need to show more of the same notification you need a list of notification objects.

For window-less example see this answer.

Community
  • 1
  • 1
Fenikso
  • 9,251
  • 5
  • 44
  • 72
1

UPDATE

Seems you don't need to call

Gdk.threads_init()

Don't remember the circumstances I tested this but could've sworn that's was made the difference for me.

Updated example:

import sys

from gi.repository import Notify
from gi.repository import Gtk

if not Notify.init('Notification Test'):
    print("ERROR: Could not init Notify.")
    sys.exit(1)

notification = Notify.Notification.new(
    "Notification Title",
    "Message...")

notification.set_urgency(Notify.Urgency.NORMAL)
def actionCallback(notification, action, user_data = None):
    print("Callback called:"+action)
    Gtk.main_quit()

notification.add_action("test-action", "Test Action", actionCallback)

if not notification.show():
    print("ERROR: Could not show notification.")
    sys.exit(2)

Gtk.main()
olivervbk
  • 276
  • 2
  • 11
  • `Gdk.threads_init()` is actually not needed in PyGObject 3.10.2+. Your example works because you still hold reference to `notification` when you call `Gtk.main()` and does not solve the problem OP is having. – Fenikso Sep 29 '15 at 08:40