"Elijah Newren" newren@gmail.com wrote:
On 7/7/06, Havoc Pennington hp@redhat.com wrote:
Currently what appears to be triggering the issue in metacity is that the window's minimum and maximum size are also changed, such that the window is not resizable. There's an exception to this rule if the window is already fullscreen-size, but the exception kicks in only for undecorated windows.
I'd try just removing the !decorated line from metacity, or testing this theory by building a version of WINE that disables decorations in this case, just to see if it helps.
I'm pretty sure that would fix this issue for WINE apps, since WINE is manually sending a please-put-this-app-in-fullscreen-mode message on behalf of the app. We should probably also fix the heuristics in src/stack.c:window_is_fullscreen_size() as well for other apps. (The difference between the two pieces of code is _allowing_ an app to be fullscreened in the first case, and automatically making an app be fullscreen without it properly requesting it in the second) I filed this pair of issues at http://bugzilla.gnome.org/show_bug.cgi?id=346927.
I'll try to provide some investigation based on the todays Wine snapshot running a demo of game Thief:
Here the game creates its main window:
trace:win:WIN_CreateWindowEx "Thief 1.33 " "LookingGlassTechnologies_WindowsGameShell_v2" ex=00000000 style=02ca0000 0,0 640x512 parent=(nil) menu=(nil) inst=0x400000 params=(nil) trace:win:dump_window_styles style: WS_CLIPCHILDREN WS_CAPTION WS_SYSMENU WS_MINIMIZEBOX trace:win:dump_window_styles exstyle:
trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,512) client (0,0)-(640,512) style 06ca0000 trace:x11drv:create_icon_window created 2000002 trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,512) trace:win:WINPOS_GetMinMaxInfo 1282 1026 / -1 -1 / 1288 1032 / 108 27 trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,512) client (0,0)-(640,512) style 06ca0000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 3,22,634x487 after 6609462c changes=f trace:x11drv:X11DRV_CreateWindow hwnd 0x10024 cs 0,0 640x512 trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,512) client (3,22)-(637,509) style 06ca0000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 3,22,634x487 after 6609462c changes=40 trace:x11drv:X11DRV_CreateWindow win 0x10024 window 0,0,640,512 client 3,22,637,509 whole 3,22,637,509 X client 0,0,634,487 xwin 2000001 trace:win:WIN_CreateWindowEx created window 0x10024 trace:win:SetForegroundWindow 0x10024 trace:event:process_events ConfigureNotify for hwnd/window 0x10024/2000001 trace:x11drv:X11DRV_ConfigureNotify win 0x10024 new X rect 3,22,634x487 (event 3,22,634x487) trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,512) trace:event:process_events processed 1 events trace:win:SetFocus 0x10024 prev (nil) trace:x11drv:X11DRV_ShowWindow hwnd=0x10024, cmd=0, wasVisible 0 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ALLCHILDREN RDW_UPDATENOW trace:x11drv:X11DRV_ShowWindow hwnd=0x10024, cmd=0, wasVisible 0 trace:win:alloc_winproc reusing 0xffff000c for 0x2034b314/(nil) fixme:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x7ff401a8)->((nil),00000008) fixme:d3d:IWineD3DStateBlockImpl_Release Releasing primary stateblock trace:win:alloc_winproc reusing 0xffff000c for 0x2034b314/(nil) trace:win:WIN_SetWindowLong 0x10024 -20 8 A trace:win:WIN_SetWindowLong 0x10024 -20 8 A
Now the game changes style of its man window to WS_POPUP (top level window without any decorations)
trace:win:WIN_SetWindowLong 0x10024 -16 80000000 A
... and calls ShowWindow(SW_SHOW) on it:
trace:x11drv:X11DRV_ShowWindow hwnd=0x10024, cmd=5, wasVisible 0 trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,0 (0x0), flags 00000043 trace:win:dump_winpos_flags flags: SWP_NOSIZE SWP_NOMOVE SWP_SHOWWINDOW trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00000043 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00001843 trace:x11drv:SWP_DoWinPosChanging current (0,0)-(640,512) style 80000000 new (0,0)-(640,512) trace:x11drv:SWP_DoOwnedPopups (0x10024) hInsertAfter = (nil) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,512) client (3,22)-(637,509) style 90000000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 0,0,640x512 after 6609462c changes=4f
window 0x10024 becomes visible and mapped to the screen:
trace:x11drv:X11DRV_set_window_pos mapping win 0x10024 trace:win:SetForegroundWindow 0x10024 trace:x11drv:X11DRV_SetWindowPos status flags = 1847
[some unrelated stuff skipped]
Now the game calls ShowWindow(SW_HIDE) on its main window to hide it:
trace:x11drv:X11DRV_ShowWindow hwnd=0x10024, cmd=0, wasVisible 1 trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,0 (0x0), flags 00000083 trace:win:dump_winpos_flags flags: SWP_NOSIZE SWP_NOMOVE SWP_HIDEWINDOW trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00000083 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00001883 trace:x11drv:SWP_DoWinPosChanging current (0,0)-(640,512) style 90000000 new (0,0)-(640,512) trace:x11drv:SWP_DoOwnedPopups (0x10024) hInsertAfter = (nil) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,512) client (0,0)-(640,512) style 80000000 trace:x11drv:X11DRV_set_window_pos unmapping win 0x10024 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 0,0,640x512 after 201b9608 changes=40 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:x11drv:X11DRV_SetWindowPos status flags = 1887 trace:win:WINPOS_ActivateOtherWindow win = (nil) fg = 0x10024 trace:win:SetForegroundWindow (nil) trace:win:SetActiveWindow (nil) trace:win:WIN_SetWindowLong 0x10024 -16 6ca0000 A trace:win:WIN_SetWindowLong 0x10024 -20 8 A trace:win:WIN_SetWindowLong 0x10024 -16 80000000 A trace:win:SetForegroundWindow 0x10024
At this point WM decides to correct position of an invisible application's window (why?) 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).
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? 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 trace:event:process_events KeymapNotify for hwnd/window (nil)/0 trace:event:process_events ClientMessage for hwnd/window 0x10024/2000001 trace:event:handle_wm_protocols got take focus msg for 0x10024, enabled=1, visible=0 (style 80000000), focus=(nil), active=0x10024, fg=0x10024, last=(nil)
Note visible=0 above and style 80000000 (just WS_POPUP, there is no WS_VISIBLE).
trace:event:process_events processed 10 events trace:win:SetFocus 0x10024 prev (nil) fixme:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x7ff401a8)->(0x10024,00000051)
The game resizes its window to prepare it for future resolution change:
trace:win:MoveWindow 0x10024 320,272 640x480 1 trace:win:SetWindowPos hwnd 0x10024, after (nil), 320,272 (640x480), flags 00000014 trace:win:dump_winpos_flags flags: SWP_NOZORDER SWP_NOACTIVATE trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 320,272 640x480 flags 00000014 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 320,272 640x480 flags 00001814 trace:x11drv:SWP_DoWinPosChanging current (0,25)-(640,537) style 80000000 new (320,272)-(960,752) trace:x11drv:SWP_DoNCCalcSize hwnd 0x10024 old win (0,25)-(640,537) old client (0,25)-(640,537) new win (320,272)-(960,752) new client (320,272)-(960,752) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (320,272)-(960,752) client (320,272)-(960,752) style 80000000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 320,272,640x480 after 6609462c changes=b trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:x11drv:X11DRV_SetWindowPos status flags = 0004
Now the game calls ShowWindow(SW_SHOW) on its main window to make it visible:
trace:x11drv:X11DRV_ShowWindow hwnd=0x10024, cmd=5, wasVisible 0 trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,0 (0x0), flags 00000043 trace:win:dump_winpos_flags flags: SWP_NOSIZE SWP_NOMOVE SWP_SHOWWINDOW trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00000043 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,0 0x0 flags 00001843 trace:x11drv:SWP_DoWinPosChanging current (320,272)-(960,752) style 80000000 new (320,272)-(960,752) trace:x11drv:SWP_DoOwnedPopups (0x10024) hInsertAfter = (nil) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (320,272)-(960,752) client (320,272)-(960,752) style 90000000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 320,272,640x480 after 6609462c changes=40 trace:x11drv:X11DRV_set_window_pos mapping win 0x10024
At this point window 0x10024 has style 0x90000000 (WS_POPUP | WS_VISIBLE), i.e. it's a top level window without any decorations (caption or border), it's visible, left/top corner is at 320,272, and its dimensions are 640x480.
Note to Wine developers: the window is managed depite the fact that it has only WS_POPUP set at this point because originally it was created as overlapped with WS_CAPTION style set.
trace:win:SetForegroundWindow 0x10024 trace:x11drv:X11DRV_SetWindowPos status flags = 1847 trace:win:SetForegroundWindow 0x10024 fixme:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x7ff401a8)->(0x10024,00000008)
The game moves its main window to 0,0 in preparation to resolution change:
trace:win:SetWindowPos hwnd 0x10024, after 0xffffffff, 0,0 (640x480), flags 00000140 trace:win:dump_winpos_flags flags: SWP_SHOWWINDOW SWP_NOCOPYBITS trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after 0xffffffff, swp 0,0 640x480 flags 00000140 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after 0xffffffff, swp 0,0 640x480 flags 00001940 trace:x11drv:SWP_DoWinPosChanging current (320,272)-(960,752) style 90000000 new (0,0)-(640,480) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,480) client (0,0)-(640,480) style 90000000 trace:x11drv:X11DRV_sync_window_position setting win 2000001 pos 0,0,640x480 after 6609462c changes=43 trace:x11drv:X11DRV_set_window_pos mapping non zero size or off-screen win 0x10024 trace:win:SetForegroundWindow 0x10024 trace:x11drv:X11DRV_SetWindowPos status flags = 0805 fixme:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x7ff401a8)->(0x10024,00000051)
... and changes screen resolution to 640x480:
fixme:xrandr:X11DRV_XRandR_SetCurrentMode Cannot change screen BPP from 32 to 16 trace:xrandr:X11DRV_XRandR_SetCurrentMode Changing Resolution to 640x480 @75 Hz trace:xrandr:X11DRV_XRandR_SetCurrentMode Resizing X display to 640x480 @75 Hz trace:x11drv:X11DRV_handle_desktop_resize desktop 0x10020 change to (640x480) trace:win:GetWindowRect hwnd 0x10020 (0,0)-(1280,1024) trace:win:BeginPaint hdc = 0x1e8 box = (0,0 - 0,0), fErase = 0
Wine detects that the window 0x10024 became full screen and asks WM to change its state:
trace:x11drv:update_fullscreen_state setting fullscreen state for hwnd 0x10024 to true
For some reason the game moves the window again, but that should have no effect since actual window position is not being changed:
trace:win:MoveWindow 0x10024 0,0 640x480 1 trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,0 (640x480), flags 00000014 trace:win:dump_winpos_flags flags: SWP_NOZORDER SWP_NOACTIVATE trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 0,0 640x480 flags 00000014 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,0 640x480 flags 00001814 trace:x11drv:SWP_DoWinPosChanging current (0,0)-(640,480) style 90000000 new (0,0)-(640,480) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,0)-(640,480) client (0,0)-(640,480) style 90000000 trace:x11drv:X11DRV_set_window_pos mapping non zero size or off-screen win 0x10024 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,480) trace:win:RedrawWindow 0x10024 rect (0,0)-(640,480) flags: RDW_INVALIDATE RDW_ERASE RDW_NOCHILDREN trace:x11drv:X11DRV_SetWindowPos status flags = 1807 trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,480)
Now WM insists again to move the window below its top panel by 25 pixels (again, why?) effectively making it not a fullscrreen one.
Again, 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,640x480 (event 320,272,640x480) trace:win:GetWindowRect hwnd 0x10024 (0,0)-(640,480) trace:x11drv:X11DRV_ConfigureNotify 0x10024 moving from (0,0) to (0,25) trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,25 (640x480), 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 640x480 flags 00000015 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,25 640x480 flags 00001815 trace:x11drv:SWP_DoWinPosChanging current (0,0)-(640,480) style 90000000 new (0,25)-(640,505) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,25)-(640,505) client (0,25)-(640,505) style 90000000 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:win:RedrawWindow 0x10024 rect (0,0)-(640,480) flags: RDW_INVALIDATE RDW_ERASE RDW_NOCHILDREN 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 320,272,640x480 (event 320,272,640x480) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,505) trace:x11drv:X11DRV_ConfigureNotify 0x10024 moving from (0,25) to (320,272) trace:win:SetWindowPos hwnd 0x10024, after (nil), 320,272 (640x480), flags 00000015 trace:win:dump_winpos_flags flags: SWP_NOSIZE SWP_NOZORDER SWP_NOACTIVATE trace:x11drv:X11DRV_SetWindowPos hwnd 0x10024, after (nil), swp 320,272 640x480 flags 00000015 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 320,272 640x480 flags 00001815 trace:x11drv:SWP_DoWinPosChanging current (0,25)-(640,505) style 90000000 new (320,272)-(960,752) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (320,272)-(960,752) client (320,272)-(960,752) style 90000000 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:win:RedrawWindow 0x10024 rect (0,0)-(640,480) flags: RDW_INVALIDATE RDW_ERASE RDW_NOCHILDREN 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,640x480 (event 0,25,640x480) trace:win:GetWindowRect hwnd 0x10024 (320,272)-(960,752) trace:x11drv:X11DRV_ConfigureNotify 0x10024 moving from (320,272) to (0,25) trace:win:SetWindowPos hwnd 0x10024, after (nil), 0,25 (640x480), 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 640x480 flags 00000015 trace:x11drv:SWP_DoWinPosChanging hwnd 0x10024, after (nil), swp 0,25 640x480 flags 00001815 trace:x11drv:SWP_DoWinPosChanging current (320,272)-(960,752) style 90000000 new (0,25)-(640,505) trace:x11drv:X11DRV_set_window_pos win 0x10024 window (0,25)-(640,505) client (0,25)-(640,505) style 90000000 trace:win:RedrawWindow 0x10024 whole window flags: RDW_ERASE RDW_ERASENOW RDW_FRAME trace:win:RedrawWindow 0x10024 rect (0,0)-(640,480) flags: RDW_INVALIDATE RDW_ERASE RDW_NOCHILDREN 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,640x480 (event 0,25,640x480) trace:win:GetWindowRect hwnd 0x10024 (0,25)-(640,505)
[end of the interesting parts of the log]
The log above makes me ask several questions:
1. 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.
2. How that could happen that the WM maps a window to the screen although it clearly was not asked to?
I hope that the log above will help to shed some light into the investigated problem and will allow to find a resolution to it.
If you need I can provide a similar log for KDE to compare how it behaves in the same situation.
Many thanks for you help.