<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def wait_for_zero_canvases(middle_mouse_close=False):
 """ Wait for all canvases to be closed, or CTRL-c. If `middle_mouse_close`, middle click will shut the canvas. incpy.ignore """

    if not __ACTIVE:
        wait_failover(wait_for_zero_canvases)
        return

    @dispatcher
    def count_canvases():
        """
        Count the number of active canvases and finish gApplication.Run()
        if there are none remaining.

        incpy.ignore
        """
        if not get_visible_canvases():
            try:
                ROOT.gSystem.ExitLoop()
            except AttributeError:
                # We might be exiting and ROOT.gROOT will raise an AttributeError
                pass

    @dispatcher
    def exit_application_loop():
        """
        Signal handler for CTRL-c to cause gApplication.Run() to finish.

        incpy.ignore
        """
        ROOT.gSystem.ExitLoop()

    # Handle CTRL-c
    sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)
    sh.Add()
    sh.Connect("Notified()", "TPyDispatcher",
               exit_application_loop, "Dispatch()")

    visible_canvases = get_visible_canvases()

    for canvas in visible_canvases:
        log.debug("waiting for canvas {0} to close".format(canvas.GetName()))
        canvas.Update()

        if middle_mouse_close:
            attach_event_handler(canvas)

        if not getattr(canvas, "_py_close_dispatcher_attached", False):
            # Attach a handler only once to each canvas
            canvas._py_close_dispatcher_attached = True
            canvas.Connect("Closed()", "TPyDispatcher",
                           count_canvases, "Dispatch()")
            keepalive(canvas, count_canvases)

    if visible_canvases and not ROOT.gROOT.IsBatch():
        run_application_until_done()

        # Disconnect from canvases
        for canvas in visible_canvases:
            if getattr(canvas, "_py_close_dispatcher_attached", False):
                canvas._py_close_dispatcher_attached = False
                canvas.Disconnect("Closed()", count_canvases, "Dispatch()")