Dmitry Timoshkov wrote:
At this point WM decides to correct position of an invisible application's window (why?)
In the metacity log, this is in the proper order (the window is mapped, metacity sets its position, and the window is withdrawn). I would conclude that this is a race; remember that if the app calls map, unmap then some events that occurred prior to the unmap request can still arrive after the unmap request. This is the asynchronicity I was talking about.
to shift it below the top GNOME top panel by 25 pixels (btw,
that's why I wrongly thought that the top GNOME top panel remained above in Z order of the main game's window, actually they do not overlap each other).
Metacity does this with all windows (keeps them below the panel) unless there's some reason not to (such as fullscreen); it's a longstanding UI decision.
For some reason WM does this in a very inefficient way in multiple steps:
trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 0,25,640x512 (event 0,0,640x512) trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,512) trace:x11drv:X11DRV_ConfigureNotify 0x10024 moving from (0,0) to (0,25) trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,25 (640x512), flags 00000015 trace:win:dump_winpos_flags flags: SWP_NOSIZE SWP_NOZORDER SWP_NOACTIVATE trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 0,25 640x512 flags 00000015 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,25 640x512 flags 00001815 trace:x11drv:SWP_DoWinPosChanging current (0,0)-(640,512) style 80000000 new (0,25)-(640,537) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,25)-(640,537) client (0,25)-(640,537) style 80000000 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:x11drv:X11DRV_SetWindowPos status flags = 0805 trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 0,25,640x512 (event 0,25,640x512) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,537) trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 0,25,640x512 (event 0,25,640x512) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,537) trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 0,25,640x512 (event 0,25,640x512) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,537) trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 0,25,640x512 (event 0,25,640x512) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,537) trace:event:process_events MapNotify for hwnd/window 0x10024/2000001
Last line above confuses a lot: why WM behind our back maps a window? What may be a reason behind that?
From the metacity log, it looks to me like WINE here withdraws the window, turns on window decorations, then remaps the window.
Metacity then has to unmap/map one more time in order to place the window inside its window frame. Undecorated windows don't have a frame so don't have the extra unmap/map caused by reparenting, but normal windows do.
Clients and WMs both have to distinguish between maps that are incidental to implementation details and maps that have a meaning in the ICCCM. Essentially you need a "withdrawn" flag on windows indicating whether you have yourself mapped or unmapped the window. The WM may also map/unmap in order to reparent, manage workspaces, etc. and you should just ignore those map events most of the time.
If you need a "steady state" mapped status that matches the Windows API, then you would need to "simulate" it on the client side, by e.g. using the client-side withdrawn flag instead of the mapped state.
That leads to a lot of confusion later: Wine thinks that a window is not visible and ignores take focus client message below, while WM starts to send focus messages to the window:
trace:event:process_events Expose for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_Expose win 0x10024 (2000001) 0,0 640x512 trace:win:RedrawWindow 0x10024 rect (0,0)-(640,512) flags: RDW_INVALIDATE RDW_ERASE RDW_ALLCHILDREN trace:event:process_events FocusIn for hwnd/window 0x10024/2000001 trace:event:EVENT_FocusIn win 0x10024 xwin 2000001 detail=NotifyNonlinear
X will not send focus events to unmapped windows btw, if it's useful to rely on that behavior.
The log above makes me ask several questions:
- Why the WM thinks that it knows better than the app where to place
its window and insists on moving it to another position? That's not a user related interaction related to moving a window using mouse or a keyboard, IMO the WM should not do this kind of things behind applications back.
As I mentioned before, there is no way to tell in the WM what is user-initiated and what isn't, so any policies on window positioning have to be for all configure requests (though the WM can and does adjust the policy for window type, etc.).
metacity keeps windows from overlapping the panel because most of the time that results in a better UI; this isn't anything new, it's been in GNOME for years.
Plenty of just normal document editor or dialog type windows try to open at 0,0 (which in GNOME would cover up the applications launcher menu) so metacity keeps them underneath that. It'd be pretty annoying to use GNOME otherwise.
A philosophical problem here is that you're trying to be a managed window and trying to do everything yourself at the same time. This can be done, but tends to be the hard path; the easy paths are to just be override redirect (though I consider that broken, it may be required to make wine work) or to just let the WM do everything (e.g. set the fullscreen state and don't do your own resizing, undecorating, and so forth that might confuse matters).
Some ideas: - if setting the vid mode viewport presumably you will also end up needing to grab the pointer... in this case there's little downside to using override redirect since no "window management" is possible anyhow - figure out how to get the fullscreen state set... unfortunately metacity doesn't understand vid modes, which will make this not really work right - patch metacity to understand vid modes (are there "vid mode events"?) - could you put the vid mode viewport in a different place, e.g. in the middle of the screen, then offset all Windows positions requests to the viewport? (too much of a hack? would it work?)
- How that could happen that the WM maps a window to the screen
although it clearly was not asked to?
If your window is withdrawn, it would be a bad bug for the WM to map it; but in the metacity log I see no evidence of this happening. However, if your window is currently in the normal/managed state, the WM _must_ unmap/map from time to time in order to work; WMs work in different ways but e.g. creating the frame by ReparentWindow to the frame window is pretty standard and causes unmap/map events. Metacity also implements multiple workspaces and minimization by unmapping, it's a bit unusual to do workspaces this way, but many or even most WMs do minimization this way.
Havoc