Commits

Steve Borho committed e0e4fa3

hggtk/hgthread: thread-safe dialog mechanism for GtkUi

  • Participants
  • Parent commits fb0362a

Comments (0)

Files changed (4)

     dialog.destroy()
     return response
 
-def entry_dialog(msg, visible=True, default='', title="TortoiseHg Prompt"):
+def entry_dialog(msg, visible=True, default='', respfunc=None):
     """ Allow a user to enter a text string (username/password)
-    
-    :param type: message dialog type
-    
     :param message: the message you want to display.
+    :param visible: should reponse be visible to user
+    :param default: default response text
+    :param respfunc: callback function for when dialog exits
+    :returns if respfunc returns dialog, else return response text
     """
     dialog = gtk.Dialog(flags=gtk.DIALOG_MODAL,
             buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK))
-    dialog.set_title(title)
+    dialog.set_title('TortoiseHg Prompt')
     entry = gtk.Entry()
     entry.set_text(default or '')
     entry.set_visibility(visible)
     dialog.vbox.set_spacing(6)
     dialog.set_default_response(gtk.RESPONSE_OK)
     dialog.show_all()
-    response = dialog.run()
-    if response == gtk.RESPONSE_OK:
-        text = entry.get_text()
+    if respfunc:
+        dialog.connect('response', respfunc)
+        dialog.entry = entry
+        return dialog
     else:
-        text = None
-    dialog.destroy()
-    return text
+        response = dialog.run()
+        if response == gtk.RESPONSE_OK:
+            text = entry.get_text()
+        else:
+            text = None
+        dialog.destroy()
+        return text
 
 def error_dialog(primary, secondary):
     """ Display an error dialog with the given message. """
         """
         Handle all the messages currently in the queue (if any).
         """
+        self.hgthread.process_dialogs()
         enditer = self.textbuffer.get_end_iter()
         while self.hgthread.getqueue().qsize():
             try:
 
 class GtkUi(ui.ui):
     queue = Queue.Queue()
+    lock = threading.Lock()
+    dialogq = Queue.Queue()
+    responseq = Queue.Queue()
 
     '''PyGtk enabled mercurial.ui subclass'''
     def __init__(self, verbose=False, debug=False, quiet=False,
         while True:
             try:
                 # Show text entry dialog with msg prompt
-                gtk.gdk.threads_enter()
-                r = entry_dialog(msg, default=default)
-                gtk.gdk.flush()
-                gtk.gdk.threads_leave()
+                self.lock.acquire()
+                self.dialogq.put( (msg, True, default) )
+                r = self.responseq.get(True)
+                self.lock.release()
                 if not r:
                     return default
                 if not pat or re.match(pat, r):
 
     def getpass(self, prompt=None, default=None):
         '''generic PyGtk password prompt dialog'''
-        gtk.gdk.threads_enter()
-        p = entry_dialog(prompt or _('password: '), visible=False,
-                default=default)
-        gtk.gdk.flush()
-        gtk.gdk.threads_leave()
+        self.lock.acquire()
+        self.dialogq.put( (prompt or _('password: '), False, default) )
+        r = self.responseq.get(True)
+        self.lock.release()
         return p
 
     def print_exc(self):
         '''
         return self.ret
 
+    def process_dialogs(self):
+        '''Polled every 10ms to serve dialogs for the background thread'''
+        try:
+            (prompt, visible, default) = GtkUi.dialogq.get_nowait()
+            self.dlg = entry_dialog(prompt, visible, default,
+                    self.dialog_response)
+        except Queue.Empty:
+            pass
+
+    def dialog_response(self, widget, response_id):
+        if response_id == gtk.RESPONSE_OK:
+            text = self.dlg.entry.get_text()
+        else:
+            text = None
+        self.dlg.destroy()
+        GtkUi.responseq.put(text)
+
     def run(self):
         # Monkey patch our GUI ui subclass into place
         if not hasattr(ui.ui, 'queue'):
         """
         Handle all the messages currently in the queue (if any).
         """
+        self.hgthread.process_dialogs()
         while self.hgthread.getqueue().qsize():
             try:
                 msg = self.hgthread.getqueue().get(0)