Hmm... I think Yiannis is right here.
Although I love asynchronous execution, and it is a good idea, I don't think it is helpful in this particular case. The benefits of asynchronous operations are that although everything is in fact slower, the user perceives differently as he can work on while things happen in the background. This is not the case here.
You cannot start working on a project before it is fully loaded, so there is no benefit unless you work on a different project that is already open. However, you do open a project because you want to work on that one, not on another.
Thus, asynchronous loading even makes the actual problem worse (and it adds to complexity, and pushes even more messages onto the already busy message queue, too).
Maybe optimizing cbProject::Open is worth a consideration. One of the nice things in Code::Blocks is that everything is coded "the very safe, very obvious way". Clarity rather than maximum speed. This is a good thing really, it works very well and possibly catches problems that one did not think about in the first place. Also, it is very easy to follow the code and to see what is going on. Plus, speed does not matter 99% of the time, at all. Every PC can handle a few extra calls and a few indirections without any noticeable penalty.
With cbProject::Open, things are different, however. Loading projects is noticeable, even painful sometimes. So maybe here, doing a few speed optimisations might really be advantageous.
While opening a large project (~700 files), Code::Blocks spends amazing amounts of CPU time in CalculateCommonTopLevelPath (and in various wxFileName functions called from other places, and wxString::ConcatSelf). Surprisingly, the many tinyxml function calls sum up to only about 2.5% total CPU time. I would have expected a lot more. Tinyxml is really awesome.
One could try to do some more result caching in a few places to avoid function calls and double-triple-quadruple indirections, and might consider not calling SetModified(false) which is a lot more expensive than it sounds (and not necessary).
Many wxWindows functions are a lot more expensive than they look, too. For example, wxFileName::GetPathSeparator() looks quite innocent. That function is probably inlined and returns a reference to a const wxString or something, right? You wish.
In fact it is a non-inline static function which calls another non-inline function that goes through a non-const switch statement (and calls yet another function for the switch argument), creates a temporary wxString object (default constructor), explicitely assigns a constant string and uses operator[] on the temporary.
When you concatenate the resulting wxChar to a wxString (the typical thing to do), another temporary is implicitely created. Clearly, you don't want to do that a few thousand times in a row.
The other wxFileName functions are still a lot more expensive (many of them in fact call GetPathSeparator() one or several times), so if one can only save one or two calls for every file opened, a lot could be gained.
Maybe it is possible to make project loading 2-3 times faster by doing some magic here and some magic there. Then nobody would bother about project loading any more at all. Just my thoughts.