docs: def qteRegisterMacro(self, macroCls, replaceMacro: bool=False,
                           macroName: str=None):
          """
          Register a macro.
  
          If ``macroName`` is **None** then its named is deduced from
          its class name (see ``qteMacroNameMangling`` for details).
  
          Multiple macros with the same name can co-exist as long as
          their applet- and widget signatures, as reported by the
          ``qteAppletSignature`` and ``qteWidgetSignature`` methods,
          differ. If ``macroCls`` has the same name and signatures as an
          already registered macro then the ``replaceMacro`` flag
          decides:
  
          * **True**: the existing macro will be replaced for all
            applet- and widget signatures specified by the new macro
            ``macroCls``.
          * **False**: the ``macroCls`` will not be registered.
  
          The method returns **None** if an error occurred (eg. the
          macro constructor is faulty), or the macro name as a
          string. If a macro was already registered and not replaced
          (ie. ``replaceMacro``) then the macro name is returned
          nonetheless.
  
          .. note:: if an existing macro is replaced the old macro
             is not deleted (it probably should be, though).
  
          |Args|
  
          * ``macroCls`` (**QtmacsMacro**): QtmacsMacro or derived
            (not type checked!)
          * ``replaceMacro`` (**bool**): whether or not to replace
            an existing macro.
          * ``macroName`` (**str**): the name under which the macro
            should be registered.
  
          |Returns|
  
          **str**: the name of the just registered macro, or **None** if
            that failed.
  
          |Raises|
  
          * **QtmacsArgumentError** if at least one argument has an invalid type.
          """
          # Check type of input arguments.
          if not issubclass(macroCls, QtmacsMacro):
              args = ('macroCls', 'class QtmacsMacro', inspect.stack()[0][3])
              raise QtmacsArgumentError(*args)
  
          # Try to instantiate the macro class.
          try:
              macroObj = macroCls()
          except Exception:
              msg = 'The macro <b>{}</b> has a faulty constructor.'
              msg = msg.format(macroCls.__name__)
  
              self.qteLogger.error(msg, stack_info=True)
              return None
  
          # The three options to determine the macro name, in order of
          # precedence, are: passed to this function, specified in the
          # macro constructor, name mangled.
          if macroName is None:
              # No macro name was passed to the function.
              if macroObj.qteMacroName() is None:
                  # The macro has already named itself.
                  macroName = self.qteMacroNameMangling(macroCls)
              else:
                  # The macro name is inferred from the class name.
                  macroName = macroObj.qteMacroName()
  
          # Let the macro know under which name it is known inside Qtmacs.
          macroObj._qteMacroName = macroName
  
          # Ensure the macro has applet signatures.
          if len(macroObj.qteAppletSignature()) == 0:
              msg = 'Macro <b>{}</b> has no applet signatures.'.format(macroName)
              self.qteLogger.error(msg, stack_info=True)
              return None
  
          # Ensure the macro has widget signatures.
          if len(macroObj.qteWidgetSignature()) == 0:
              msg = 'Macro <b>{}</b> has no widget signatures.'.format(macroName)
              self.qteLogger.error(msg, stack_info=True)
              return None
  
          # Flag to indicate that at least one new macro type was
          # registered.
          anyRegistered = False
  
          # Iterate over all applet signatures.
          for app_sig in macroObj.qteAppletSignature():
              # Iterate over all widget signatures.
              for wid_sig in macroObj.qteWidgetSignature():
                  # Infer the macro name from the class name of the
                  # passed macro object.
                  macroNameInternal = (macroName, app_sig, wid_sig)
  
                  # If a macro with this name already exists then either
                  # replace it, or skip the registration process for the
                  # new one.
                  if macroNameInternal in self._qteRegistryMacros:
                      if replaceMacro:
                          # Remove existing macro.
                          tmp = self._qteRegistryMacros.pop(macroNameInternal)
                          msg = 'Replacing existing macro <b>{}</b> with new {}.'
                          msg = msg.format(macroNameInternal, macroObj)
                          self.qteLogger.info(msg)
                          tmp.deleteLater()
                      else:
                          msg = 'Macro <b>{}</b> already exists (not replaced).'
                          msg = msg.format(macroNameInternal)
                          self.qteLogger.info(msg)
                          # Macro was not registered for this widget
                          # signature.
                          continue
  
                  # Add macro object to the registry.
                  self._qteRegistryMacros[macroNameInternal] = macroObj
                  msg = ('Macro <b>{}</b> successfully registered.'
                         .format(macroNameInternal))
                  self.qteLogger.info(msg)
                  anyRegistered = True
  
          # Return the name of the macro, irrespective of whether or not
          # it is a newly created macro, or if the old macro was kept
          # (in case of a name conflict).
          return macroName