wine's fullscreen code has no effect on metacity

Dmitry Timoshkov dmitry at codeweavers.com
Tue Jul 11 11:04:27 CDT 2006


"Elijah Newren" <newren at gmail.com> wrote:

> On 7/7/06, Havoc Pennington <hp at 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.

-- 
Dmitry. 




More information about the wine-devel mailing list