Skip to content

Commit

Permalink
Attempt to remove all gdk threads_enter and leave calls
Browse files Browse the repository at this point in the history
Changed used module for handling of threads from _thread
to threading. Threading has better API and allows us to
distinguish threads more easily. However there is a minor problem.
When Gdk Window is passed as a argument to method executed in
different thread then it is converted before execution of method
into Gtk box. That is why i removed parent argument from connect
method of GUI class.

Parent argument has been removed from connect method of GUI class.
Reasons described above. Connect was always called with the same
parent anyway so this does not change its function.

Added thread_operations.py file. It contains decorator which
simulates some functionalities provided by deprecated
functions.

Some calls of deprecated functions have been replaced by
Gdk_threads_add_idle function.
  • Loading branch information
TomasKorbar committed Jun 4, 2019
1 parent e58d4c9 commit d9c828e
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 60 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ nobase_pkgdata_DATA= \
smburi.py \
statereason.py \
timedops.py \
thread_operations.py \
ToolbarSearchEntry.py \
userdefault.py \
ui/AboutDialog.ui \
Expand Down
113 changes: 53 additions & 60 deletions system-config-printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 ()
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -1178,19 +1180,17 @@ 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,
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

Expand All @@ -1207,7 +1207,7 @@ def on_cancel_connect_clicked(self, widget):
self.connect_thread = None
self.ConnectingDialog.hide()

def connect(self, parent=None):
def connect(self):
"""
Open a connection to a new server. Is executed in a separate thread!
"""
Expand All @@ -1232,42 +1232,44 @@ def connect(self, parent=None):
nonfatalException ()

try:
connection = authconn.Connection(parent,
connection = authconn.Connection(self.PrintersWindow,
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, self.PrintersWindow
)
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, self.PrintersWindow
)
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()
Expand All @@ -1276,12 +1278,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, self.PrintersWindow
)
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
Expand Down Expand Up @@ -2058,23 +2061,19 @@ 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,
None
)


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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
30 changes: 30 additions & 0 deletions thread_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import threading
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk, GLib

SCP_MAIN_THREAD_NAME = "SCP_MAIN_THREAD"

def thread_safe_blocking_call(function):
""" Make function/method thread safe and block until its call is finished
"""

blocker = threading.Event()

def inner_wrapper(*args, **kwargs):
function(*args, **kwargs)
blocker.set()
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
)
blocker.wait()

return wrapper

0 comments on commit d9c828e

Please sign in to comment.