The attached C sample demonstrates two problems with using ShowWindow(hwnd,SW_SHOWMINIMIZED) to minimise a top level window. The tests were done in KDE, but the second problem has been confirmed in Gnome and I suspect the first also occurs there.
1. If you start this program without arguments and click on the resulting window it will correctly minimise, but when restored it will appear with size 32x32 in the lower left hand corner of the screen (that is, as if it were still minimised as an icon).
2. If you start this program with any argument, the window will not appear at all. It should appear minimised.
The first problem can be fixed by the attached hack (presumably this is not the correct fix or even anything approximating a correct fix). The second seems hairier and my best guess is that it happens that way because the window manager has not mapped the window yet.
Troy Rollo wrote:
The attached C sample demonstrates two problems with using ShowWindow(hwnd,SW_SHOWMINIMIZED) to minimise a top level window. The tests were done in KDE, but the second problem has been confirmed in Gnome and I suspect the first also occurs there.
The problem is that we should ask the Window manager to minimize us. There's a hack in CrossOver that "fixes" it, which I've attached. If you're in a good mood, try getting it accepted into Wine. :)
I haven't tested that this patch works as is... however it should be complete, and at least compiles.
Mike
diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 5fdde83..33370df 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -923,12 +923,42 @@ UINT WINPOS_MinMaximize( HWND hwnd, UINT return swpFlags; }
+/*********************************************************************** + * X11DRV_WMMinimizeWindow + * + * See the ICCCM section 4.1.4. Changing Window State for more details. + * http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.4 + */ +static BOOL X11DRV_WMMinimizeWindow(HWND hwnd) +{ + XEvent xev; + + TRACE("%p\n", hwnd); + + wine_tsx11_lock(); + + xev.xclient.type = ClientMessage; + xev.xclient.window = X11DRV_get_whole_window( hwnd ); + xev.xclient.message_type = x11drv_atom(WM_CHANGE_STATE); + xev.xclient.serial = 0; + xev.xclient.display = thread_display(); + xev.xclient.send_event = True; + xev.xclient.format = 32; + xev.xclient.data.l[0] = IconicState; + xev.xclient.data.l[2] = 0; + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + + wine_tsx11_unlock(); + + return TRUE; +}
/*********************************************************************** * ShowWindow (X11DRV.@) */ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) { + Display *display = thread_display(); WND *wndPtr; HWND parent; LONG style = GetWindowLongW( hwnd, GWL_STYLE ); @@ -957,6 +987,19 @@ BOOL X11DRV_ShowWindow( HWND hwnd, INT c swp |= SWP_SHOWWINDOW; /* fall through */ case SW_MINIMIZE: + + /* handle minimize a different way */ + if ((root_window == DefaultRootWindow(display)) && + GetAncestor(hwnd,GA_PARENT) == GetDesktopWindow()) + { + if( !(style & WS_MINIMIZE) ) + { + X11DRV_WMMinimizeWindow( hwnd ); + WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE ); + } + return wasVisible; + } + swp |= SWP_FRAMECHANGED; if( !(style & WS_MINIMIZE) ) swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos ); diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index d259c86..9e8c3d9 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -561,6 +561,7 @@ enum x11drv_atoms XATOM_WM_PROTOCOLS, XATOM_WM_DELETE_WINDOW, XATOM_WM_TAKE_FOCUS, + XATOM_WM_CHANGE_STATE, XATOM_KWM_DOCKWINDOW, XATOM_DndProtocol, XATOM_DndSelection, diff --git a/dlls/x11drv/x11drv_main.c b/dlls/x11drv/x11drv_main.c index f0269a9..322ffd7 100644 --- a/dlls/x11drv/x11drv_main.c +++ b/dlls/x11drv/x11drv_main.c @@ -123,6 +123,7 @@ static const char * const atom_names[NB_ "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_TAKE_FOCUS", + "WM_CHANGE_STATE", "KWM_DOCKWINDOW", "DndProtocol", "DndSelection",
On Tuesday 16 May 2006 19:15, Mike McCormack wrote:
The problem is that we should ask the Window manager to minimize us.
This is what the XIconifyWindow call (made in X11DRV_set_iconic_state in dlls/x11drv/window.c, called by WINPOS_MinMaximise, called by the SW_MINIMIZE and SW_SHOWMINIMIZED cases in X11DRV_ShowWindow) is documented as doing - in fact based on the description of XIconifyWindow (without checking its source code), it seems your X11DRV_WMMinimizeWindow is just a reimplementation of that.
There's a hack in CrossOver that "fixes" it, which I've attached. If you're in a good mood, try getting it accepted into Wine. :)
This deals with the first case (calling ShowWindow(hwnd, SW_SHOWMINIMIZED) on a mouse event), but not the second (making the same call immediately after CreateWindow() without WS_VISIBLE).
Your hack thus gives the same results as mine (mine just stopped X11DRV_ShowWindow from doing extra stuff after XIconifyWindow).
This modified hack fixes both cases, but presumably is going to break unmanaged windows.