code: def async_call(func, *args, callback=None):
      '''Call `func` in background thread, and then call `callback` in Gtk main thread.
  
      If error occurs in `func`, error will keep the traceback and passed to
      `callback` as second parameter. Always check `error` is not None.
      '''
      def do_call():
          result = None
          error = None
  
          try:
              result = func(*args)
          except Exception:
              error = traceback.format_exc()
              logger.error(error)
          if callback:
              GLib.idle_add(callback, result, error)
  
      thread = threading.Thread(target=do_call)
      thread.daemon = True
      thread.start(f async_call(func, *args, callback=None):
      '''Call `func` in background thread, and then call `callback` in Gtk main thread.
  
      If error occurs in `func`, error will keep the traceback and passed to
      `callback` as second parameter. Always check `error` is not None.
      '''
      def do_call():
          result = None
          error = None
  
          try:
              result = func(*args)
          except Exception:
              error = traceback.format_exc()
              logger.error(error)
          if callback:
              GLib.idle_add(callback, result, error)
  
      thread = threading.Thread(target=do_call)
      thread.daemon = True
      thread.start()
docs: Call `func` in background thread, and then call `callback` in Gtk main thread.
  
      If error occurs in `func`, error will keep the traceback and passed to
      `callback` as second parameter. Always check `error` is not None.