I recall there was an Ada X11 server (Mitre?) that used tasks instead of a single event loop, although they may have been papering over an event loop underneath.
X11 server side is a bit different case - generally you control all message flows there in custom way.
The windows message loop is essentially something you can create per thread, and "GUI" programs have one initialized for them (thus WinMain instead of main in C).
But you need no special work to create more threads with more loops, in fact making every top-level window a separate thread is trivial (doing it for sub-windows like widgets might be slightly more complex though).
macOS/iOS/etc have a central event loop in Cocoa - what more only initial thread is allowed to talk with windowserver!
Xlib pretty much enforced single event loop per connection - XCB allowed more.
In comparison, win32 applications can create an event loop ("message pump") per thread, and you can use GUI calls completely independently on them.