async def _send_dbus_message(
    session_bus: bool,
    message_type: MessageType,
    destination: str | None,
    interface: str | None,
    path: str | None,
    member: str | None,
    signature: str,
    body: Any,
    negotiate_unix_fd: bool = False,
    bus: MessageBus | None = None,
    preserve: bool = False,
) -> tuple[MessageBus | None, Message | None]:
    """
    Private method to send messages to dbus via dbus_fast.

    An existing bus connection can be passed, if left empty, a new
    bus connection will be created.

    Returns a tuple of the bus object and message response.
    """
    if bus is None:
        if session_bus:
            bus_type = BusType.SESSION
        else:
            bus_type = BusType.SYSTEM

        try:
            bus = await MessageBus(
                bus_type=bus_type, negotiate_unix_fd=negotiate_unix_fd
            ).connect()
        except (AuthError, Exception):
            logger.warning("Unable to connect to dbus.")
            return None, None

    if isinstance(body, str):
        body = [body]

    # Ignore types here: dbus-fast has default values of `None` for certain
    # parameters but the signature is `str` so passing `None` results in an
    # error in mypy.
    msg = await bus.call(
        Message(
            message_type=message_type,
            destination=destination,
            interface=interface,
            path=path,
            member=member,
            signature=signature,
            body=body,
        )
    )

    # Keep details of bus connections so we can close them on exit
    # dbus_bus_connetions is a set so we don't need to worry about
    # duplicates
    if not preserve:
        dbus_bus_connections.add(bus)

    return bus, msg

    Private method to send messages to dbus via dbus_fast.

    An existing bus connection can be passed, if left empty, a new
    bus connection will be created.

    Returns a tuple of the bus object and message response.
    
libqtile/utils.py