What I wanted is this:
a) normal startup:
- the application starts, and creates a main frame
- all plugins are loaded, plugins can install whatever loggers they might need later (no GUI available yet)
- the main frame queries the installed loggers for controls
- if a logger has a control, it's added to the info pane (now GUI is available, and output is visible)
b) batch startup:
- the application either does not create a main frame at all (not needed) or, if that is a problem for some reason, creates one but doesn't show it
- only the compiler plugin (and maybe 1-2 other select plugins, such as EnvVar) is loaded, as nothing else is needed
- a simple window is created, just a plain normal window
- the compiler's log is asked for a control, which is added to the window (everything else is just ignored, it doesn't matter)
- batch build runs, finishes, compiler plugin unregisters its logger, the window is closed, the application is closed
- no need to do anything else -- the window will delete the control, and LogManager will delete the Logger
- if we are sure that the compiler does not output anything after the build is finished (a reasonable assumption) then we don't even need to unregister the Logger (that would keep an invalid pointer dangling around for a few milliseconds, but if it is guaranteed not to be accessed, that's ok)
- the compiler plugin (or any other component) ideally does not even know that a batch build is running (well, it still may have to know if no main frame is created, because then no menu entries and toolbar buttons can be added, but that would be trivial to check).
And what we have is this:
a) and b) likewise:
- a main frame is created and listens to messages, and in response adds controls to the info pane which is owned by either the main frame or BatchLogDialog (and, this class does not even seem to exist at all, I could not find it with code completion lookup, nor with global file search ---> how does this compile at all??? I'm clueless...)
- there are a lot of separate branches for either "normal" or "batch" mode in all involved components, although none of those components should actually need to bother
- everything is dynamic and cool, but it does not work, and it's a pain to figure why
This is another example for complexity being not a good thing. If we absolutely have to load/unload plugins at runtime (I personally don't see why we need this), there is still no reason why you have to add/remove loggers dynamically too.
It is perfectly acceptable that a custom logger (or rather, its control) stays visible if you unload a plugin at runtime (the user can still hide the tab if he doesn't want to see it), and it is perfectly acceptable that no custom logger is visible if a plugin was dynamically loaded after startup. For one reason, almost no plugin needs to install a custom logger anyway, and if it is really so utterly important, then the user can relaunch the application quickly, this is really no big burden.
Personally, I don't even think it is asked too much to relaunch the application to load a new plugin or to unload another one, it keeps things simple and failsafe, plus, you don't load/unload plugins 35 times per day anyway. Firefox which I'm using to type this text right now loads its plugins at startup, and there is nothing wrong with it.
Regarding non-Loggers added to the InfoPane, one could argue. Although I don't deem it good to add/remove controls at runtime (and move it between different panes), if this is absolutely wanted... ok then. Again, I would prefer things to be simple, but... there is one difference. Here we're talking about something that is entirely optional and entirely proprietary. What makes it acceptable is that the application does not know anything or give a crap about the pointer it is given. Thus, the complexity doesn't lie in the application or the managers.