diff --git a/system-config-printer.py b/system-config-printer.py index f3e266377..648fea0ce 100755 --- a/system-config-printer.py +++ b/system-config-printer.py @@ -23,9 +23,8 @@ # config is generated from config.py.in by configure import config - import sys, os, time, re -import _thread +import threading import dbus import gi try: @@ -94,6 +93,7 @@ def show_help(): import newprinter from newprinter import busy, ready import printerproperties +from thread_operations import thread_safe_blocking_call, SCP_MAIN_THREAD_NAME import ppdippstr ppdippstr.init () @@ -749,6 +749,7 @@ def on_server_settings_activate (self, menuitem): except RuntimeError: self.monitor.update () + @thread_safe_blocking_call def setConnected(self): connected = bool(self.cups) @@ -830,6 +831,7 @@ def getServers(self): known_servers.sort() return known_servers + @thread_safe_blocking_call def populateList(self, prompt_allowed=True): # Save selection of printers. selected_printers = set() @@ -1178,19 +1180,18 @@ def on_connect_activate(self, widget): cups.setUser('') self.connect_user = cups.getUser() # Now start a new thread for connection. - self.connect_thread = _thread.start_new_thread(self.connect, - (self.PrintersWindow,)) + self.connect_thread = threading.Thread(target=self.connect, + args=(self.PrintersWindow), + name="SCP_CONNECTING_THREAD" + ) + self.connect_thread.start() def update_connecting_pbar (self): ret = True - Gdk.threads_enter () - try: - if not self.ConnectingDialog.get_property ("visible"): - ret = False # stop animation - else: - self.pbarConnecting.pulse () - finally: - Gdk.threads_leave () + if not self.ConnectingDialog.get_property ("visible"): + ret = False # stop animation + else: + self.pbarConnecting.pulse () return ret @@ -1236,38 +1237,40 @@ def connect(self, parent=None): host=self.connect_server, encryption=self.connect_encrypt) except RuntimeError as s: - if self.connect_thread != _thread.get_ident(): return - Gdk.threads_enter() - try: - self.ConnectingDialog.hide() - self.cups = None - self.setConnected() - self.populateList() - show_IPP_Error(None, s, parent) - finally: - Gdk.threads_leave() + if self.connect_thread != threading.currentThread(): return + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + self.ConnectingDialog.hide, + ) + self.cups = None + self.setConnected() + self.populateList() + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + show_IPP_Error, + (None, s, parent) + ) return except cups.IPPError as e: (e, s) = e.args - if self.connect_thread != _thread.get_ident(): return - Gdk.threads_enter() - try: - self.ConnectingDialog.hide() - self.cups = None - self.setConnected() - self.populateList() - show_IPP_Error(e, s, parent) - finally: - Gdk.threads_leave() + if self.connect_thread != threading.currentThread(): return + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + self.ConnectingDialog.hide, + ) + self.cups = None + self.setConnected() + self.populateList() + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + show_IPP_Error, + (None, s, parent) + ) return except: nonfatalException () - if self.connect_thread != _thread.get_ident(): return - Gdk.threads_enter() - + if self.connect_thread != threading.currentThread(): return try: - self.ConnectingDialog.hide() + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + self.ConnectingDialog.hide, + ) self.cups = connection self.setConnected() self.populateList() @@ -1276,12 +1279,13 @@ def connect(self, parent=None): self.cups = None self.setConnected() self.populateList() - show_HTTP_Error(s, parent) + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + show_HTTP_Error, + (s, parent) + ) except: nonfatalException () - Gdk.threads_leave() - def reconnect (self): """Reconnect to CUPS after the server has reloaded.""" # libcups would handle the reconnection if we just told it to @@ -2058,23 +2062,18 @@ def on_start_service_reply (self, *args): GLib.timeout_add_seconds (1, self.service_started_try) def service_started_try (self): - Gdk.threads_enter () - try: - self.on_btnRefresh_clicked (None) - finally: - Gdk.threads_leave () + Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, + self.on_btnRefresh_clicked + ) + GLib.timeout_add_seconds (1, self.service_started_retry) return False def service_started_retry (self): if not self.cups: - Gdk.threads_enter () - try: self.on_btnRefresh_clicked (None) self.btnStartService.set_sensitive (True) - finally: - Gdk.threads_leave () return False @@ -2180,11 +2179,7 @@ def on_printer_modified (self, obj, name, ppd_has_changed): def defer_refresh (self): def deferred_refresh (): self.populateList_timer = None - Gdk.threads_enter () - try: - self.populateList (prompt_allowed=False) - finally: - Gdk.threads_leave () + self.populateList (prompt_allowed=False) return False if self.populateList_timer: @@ -2222,6 +2217,8 @@ def cups_connection_recovered (self, mon): def main(show_jobs): cups.setUser (os.environ.get ("CUPS_USER", cups.getUser())) + # set name for main thread + threading.currentThread().setName(SCP_MAIN_THREAD_NAME) Gdk.threads_init () from dbus.glib import DBusGMainLoop DBusGMainLoop (set_as_default=True) @@ -2233,11 +2230,7 @@ def main(show_jobs): else: mainwindow = GUI() - Gdk.threads_enter () - try: - Gtk.main() - finally: - Gdk.threads_leave () + Gtk.main() if __name__ == "__main__": import getopt diff --git a/thread_operations.py b/thread_operations.py new file mode 100644 index 000000000..7b6fc201d --- /dev/null +++ b/thread_operations.py @@ -0,0 +1,35 @@ +import threading +from gi.repository import Gdk, GLib + +SCP_MAIN_THREAD_NAME = "SCP_MAIN_THREAD" + +class Blocker(): + def __init__(self): + self.block = True + +def thread_safe_blocking_call(function): + """ Make function/method thread safe and block until its call is finished + """ + + # we need a class instance because python does not support pointers + blocker = Blocker() + + def inner_wrapper(*args, **kwargs): + function(*args, **kwargs) + blocker.block = False + return False + + def wrapper(*args, **kwargs): + # if this is the main thread then simply return function + if threading.current_thread().name == SCP_MAIN_THREAD_NAME: + return function(*args, **kwargs) + Gdk.threads_add_idle( + GLib.PRIORITY_DEFAULT_IDLE, + inner_wrapper, + *args, + **kwargs + ) + while blocker.block: + pass + + return wrapper