Introduce a global window list (a GPtrArray of GdkWindow pointers). Put all new toplevel windows into it, remove windows from it on destruction or when they lose their toplevel status.
When we raise a window, go through the list, bottom to top, and count the number of windows that should be raised (the window that the caller specified, plus any of its transient children, and their own transient children - assuming that all of them are properly above their transient parents). Then go through the list again and move all of these windows to the top, in the same order. The temporary list of all moved windows is a side-effect, which other part of the backend then uses to actually call SetWindowPos() on all the affected windows.
Same when lowering a window, but in reverse.
When the application is activated, move all of its windows to the top.
Fixes #2045 (closed) and #2439 (closed)