If I had to do this myself, I would probably go for a 2d array of logic elements (especially with a reduced scale, for example, using jdv or using accelerated graphics routines) or an arbitrary point approach.
If you really wanted to make a smarter approach, you can simply consider the rectangles. Start with a rectangle with angles (0,0), (1600,1200) = (lx, ly), (rx, ry) and subtract the first window (wx1, wy1) (wx2, wy2).
This can generate a maximum of 4 new "still available" rectangles if they are completely contained in the original free rectangle: (for example, all 4 corners of the new window are contained in the old one), they (lx, ly) - (rx, wy1), (lx , wy1) - (wx1, wy2), (wx2, wy1) - (rx, wy2) and (lx, wy2) - (rx, ry). If only the corner of the window overlaps (only one corner is inside the free rectangle), it splits it into two new rectangles; if the side (2 angles) in it are divided into 3; and if there is no coincidence, nothing changes. (If all axes are aligned, you cannot have 3 angles inside).
So, continue the loop through the windows, checking the intersection and dividing rectangles until you have a list (if any) of the remaining free space in terms of the rectangles.
This will probably be slower than any of the above approaches to the graphics library, but it would be more interesting to write :)