Search code examples
pythongtkpygtkmdi

Ending the GTK+ main loop in an Python MDI application


I am trying to code an application that consists of various windows (e.g., generic message dialog, login dialog, main interface, etc.) and am having trouble getting the gtk.main_quit function to be called: either I get a complaint about the call being outside the main loop, or the function doesn't get called at all.

I am a newbie to both Python and GTK+, but my best guess as to how to get this to work is to have a "root" window, which is just a placeholder that is never seen, but controls the application's GTK+ loop. My code, so far, is as follows:

import pygtk
pygtk.require("2.0")
import gtk

class App(gtk.Window):
  _exitStatus = 0

  # Generic message box
  def msg(self, title, text, type = gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK):
    # Must always have a button
    if buttons == gtk.BUTTONS_NONE:
      buttons = gtk.BUTTONS_OK

    dialog = gtk.MessageDialog(None, 0, type, buttons, title)
    dialog.set_title(title)
    dialog.set_geometry_hints(min_width = 300)
    dialog.set_resizable(False)
    dialog.set_deletable(False)
    dialog.set_position(gtk.WIN_POS_CENTER)
    dialog.set_modal(True)
    dialog.format_secondary_text(text)

    response = dialog.run()
    dialog.destroy()

    return response

  def nuke(self, widget, data):
    gtk.main_quit()
    exit(self._exitStatus)

  def __init__(self):
    super(App, self).__init__()
    self.connect('destroy', self.nuke)

    try:
      raise Exception()
    except:
      self.msg('OMFG!', 'WTF just happened!?', gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE)
      self._exitStatus = 1
      self.destroy()

    if self.msg('OK', 'Everything worked fine') == gtk.RESPONSE_OK:
      self.destroy()

# Let's go!
App()
gtk.main()

The nuke function never gets called, despite the explicit calls to destroy.


DIFF On @DonQuestion's advice:

- self.destroy()
+ self.emit('destroy')

- App()
+ app = App()

This didn't solve the problem...


UPDATE Accepted @jku's answer, but also see my own answer for extra information...


Solution

  • First, there is a bit of a test problem with the code: You call Gtk.main_quit() from the App initialization: this happens before main loop is even running so signals probably won't work.

    Second, you'll probably get a warning on destroy(): 'destroy' handler only takes two arguments (self plus one) but yours has three...

    Also with regards to your comment about control flow: You don't need a Window to get signals as they're a GObject feature. And for your testing needs you could write a App.test_except() function and use glib.idle_add (self.test_except) in the object initialization -- this way test_except() is called when main loop is running.