Gtk callbacks and main loop

I am trying to create a simple Unix desktop application that uses the pynotify notification system to show users some warnings and let them launch the corresponding applications using the button placed in the message.

Here is the corresponding simplified code:

import subprocess, pynotify, gobject, gtk class Notifier(): def __init__(self): pynotify.init('Notifications') n = pynotify.Notification("Some stuff") n.add_action("action", "Action", self.action_callback) n.show() gtk.main() def action_callback(self, n, action): subprocess.Popen(['ls', '/']) if __name__ == '__main__': Notifier() 

This works fine (it shows a pop-up window with a notification about the "Action" button that triggers the activation of ls / when) until I try to put part of the notification in a loop (I need to regularly poll the server to receive notifications then show).

I tried this:

 import subprocess, pynotify, gobject, gtk class Notifier(): def __init__(self): pynotify.init('Notifications') gobject.timeout_add(0, self.main) gtk.main() def action_callback(self, n, action): subprocess.Popen(['ls', '/']) def main(self): n = pynotify.Notification("Some stuff") n.add_action("action", "Action", self.action_callback) n.show() gobject.timeout_add(10000, self.main) if __name__ == '__main__': Notifier() 

but for some reason, the action_callback function is no longer called when the Action button is clicked.

This seems to be a problem with the way I use the main Gtk loop. Doing something like this makes the function actually called:

 import subprocess, pynotify, gobject, gtk class Notifier(): def __init__(self): pynotify.init('Notifications') self.main() def action_callback(self, n, action): subprocess.Popen(['ls', '/']) def main(self): n = pynotify.Notification("Some stuff") n.add_action("action", "Action", self.action_callback) n.show() gobject.timeout_add(10000, self.main) gtk.main() if __name__ == '__main__': Notifier() 

but of course, this is not the right solution, and I quickly get the "maximum recursion depth" of Python RuntimeError. However, this shows that changing the location of the gtk.main () call has a frequency.

I tried to look at the Gtk and Pygtk documentation on the main loop, but ultimately did not find a solution.

So my question is: what needs to be done and what is its logic?

TL DR . If I did not put gtk.main () in the same function that displays the notification, the action_callback function does not run when necessary. Since this function should be placed in mainkop gtk, then I was stuck in calling mainkop gtk itself or the action_callback function did not start.

Thanks in advance for any help;)

+4
source share
1 answer

The problem is that pynotify has an error with callbacks for objects without references. In your first snippet, n gets unreferenced (when counting references in cPython) when the main() function exits. Unfortunately, this means that the notification object is destroyed and the action is not called (although your notification daemon will still show the notification).

The workaround is to maintain a link to this notification. The easiest thing is to transfer your first fragment and change n = pynotify.Notification to self.last_notification = n = pynotify.Notication .

If you have several notifications, you need to drop them into a list or set, but then you will need to make sure that they are deleted, both in the case when the action is launched, and after the timeout.

+3
source

Source: https://habr.com/ru/post/1389279/


All Articles