Implement support for the EWMH fullscreening hint
Mike Hearn
mh at codeweavers.com
Thu May 27 19:21:25 CDT 2004
This let's IE fullscreen correctly in standards compliant WMs, though
it also reveals a bug in our rebar control which can cause a (temporary?)
deadlock when leaving fullscreen mode.
Mike Hearn <mh at codeweavers.com>
Implement support for the EWMH fullscreening hint.
Generated from:
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-1
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-2
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-3
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-4
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-5
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-6
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-7
* mike at navi.cx--2004/wine--fullscreen--0.9--patch-8
--- mod/dlls/x11drv/window.c
+++ mod/dlls/x11drv/window.c
@@ -74,6 +74,8 @@
"DndSelection",
"_MOTIF_WM_HINTS",
"_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_FULLSCREEN",
"_NET_WM_PID",
"_NET_WM_PING",
"_NET_WM_NAME",
@@ -114,6 +116,7 @@
inline static BOOL is_window_managed( WND *win )
{
if (!managed_mode) return FALSE;
+
/* tray window is always managed */
if (win->dwExStyle & WS_EX_TRAYWINDOW) return TRUE;
/* child windows are not managed */
@@ -126,13 +129,9 @@
if (win->dwStyle & WS_THICKFRAME) return TRUE;
/* application windows are managed */
if (win->dwExStyle & WS_EX_APPWINDOW) return TRUE;
- /* full-screen popup windows are managed */
- if ((win->dwStyle & WS_POPUP) &&
- (win->rectWindow.right-win->rectWindow.left) == screen_width &&
- (win->rectWindow.bottom-win->rectWindow.top) == screen_height)
- {
- return TRUE;
- }
+ /* windows with a system menu are managed */
+ if (win->dwStyle & WS_SYSMENU) return TRUE;
+
/* default: not managed */
return FALSE;
}
@@ -177,7 +176,6 @@
return (CWOverrideRedirect | CWSaveUnder | CWEventMask | CWColormap | CWCursor);
}
-
/***********************************************************************
* X11DRV_sync_window_style
*
@@ -354,7 +352,10 @@
size_hints->y = data->whole_rect.top;
size_hints->flags = PWinGravity | PPosition;
- if ( !(win->dwStyle & WS_THICKFRAME) )
+ /* we only want to be able to resize windows with WS_THICKFRAME.
+ * in addition, metacity refuses to fullscreen non-resizable windows
+ */
+ if ( !(win->dwStyle & WS_THICKFRAME) && !data->fullscreened)
{
size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
@@ -448,7 +449,7 @@
if (win->dwStyle & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
if (win->dwStyle & WS_SYSMENU) mwm_hints.functions |= MWM_FUNC_CLOSE;
mwm_hints.decorations = 0;
- if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) mwm_hints.decorations |= MWM_DECOR_TITLE;
+ if (((win->dwStyle & WS_CAPTION) == WS_CAPTION) && !data->fullscreened) mwm_hints.decorations |= MWM_DECOR_TITLE;
if (win->dwExStyle & WS_EX_DLGMODALFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
else if (win->dwStyle & WS_THICKFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
else if ((win->dwStyle & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
@@ -465,6 +466,15 @@
XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
+ /* for windows that are already mapped, toggle_fullscreen sends a message to the WM */
+ if (data->fullscreened && !(win->dwStyle & WS_VISIBLE)) {
+ Atom newstate = x11drv_atom(_NET_WM_STATE_FULLSCREEN);
+
+ TRACE("setting state to _NET_WM_STATE_FULLSCREEN\n");
+ XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE),
+ XA_ATOM, 32, PropModeReplace, (unsigned char*)&newstate, 1 );
+ }
+
wm_hints = XAllocWMHints();
wine_tsx11_unlock();
@@ -762,6 +772,8 @@
RECT rect;
BOOL is_top_level = is_window_top_level( win );
+ data->fullscreened = FALSE;
+
rect = win->rectWindow;
X11DRV_window_to_X_rect( win, &rect );
--- mod/dlls/x11drv/winpos.c
+++ mod/dlls/x11drv/winpos.c
@@ -3,6 +3,7 @@
*
* Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
* Copyright 1995, 1996, 1999 Alex Korobka
+ * Copyright 2004 Mike Hearn for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -74,6 +75,46 @@
/***********************************************************************
+ * toggle_fullscreen
+ *
+ * Use the NETWM fullscreening protocol to toggle fullscreened state. This only
+ * works for mapped windows.
+ */
+static void toggle_fullscreen( HWND hwnd )
+{
+ WND *win = WIN_GetPtr(hwnd);
+ struct x11drv_win_data *data = win->pDriverData;
+ XEvent xev;
+
+ TRACE("hwnd=%p, current=%s\n", hwnd, data->fullscreened ? "true" : "false");
+ data->fullscreened = !data->fullscreened;
+
+ wine_tsx11_lock();
+
+ X11DRV_set_wm_hints(thread_display(), win);
+
+ if (win->dwStyle & WS_VISIBLE) {
+ TRACE("toggling fullscreen state\n");
+ xev.xclient.type = ClientMessage;
+ xev.xclient.window = data->whole_window;
+ xev.xclient.message_type = x11drv_atom(_NET_WM_STATE);
+ xev.xclient.serial = 0;
+ xev.xclient.display = thread_display();
+ xev.xclient.send_event = True;
+ xev.xclient.format = 32;
+ /* using _NET_WM_STATE_TOGGLE here does not work correctly with some WMs */
+ xev.xclient.data.l[0] = (data->fullscreened ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE);
+ xev.xclient.data.l[1] = x11drv_atom(_NET_WM_STATE_FULLSCREEN);
+ xev.xclient.data.l[2] = 0;
+ XSendEvent(thread_display(), root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ TRACE("toggled\n");
+ }
+
+ wine_tsx11_unlock();
+ WIN_ReleasePtr(win);
+}
+
+/***********************************************************************
* clip_children
*
* Clip all children of a given window out of the visible region
@@ -861,7 +902,7 @@
if (wndPtr == WND_OTHER_PROCESS) return;
changed = wndPtr->dwStyle ^ oldStyle;
-
+
if (changed & WS_VISIBLE)
{
if (!IsRectEmpty( &wndPtr->rectWindow ))
@@ -919,12 +960,14 @@
RECT newWindowRect, newClientRect;
RECT oldWindowRect, oldClientRect;
UINT wvrFlags = 0;
- BOOL bChangePos;
+ BOOL bChangePos, fromXEvent;
+ struct x11drv_win_data *data;
TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
winpos->cx, winpos->cy, winpos->flags);
+ fromXEvent = winpos->flags & SWP_WINE_NOHOSTMOVE;
bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
@@ -949,11 +992,28 @@
if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
+ if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
+ data = wndPtr->pDriverData;
+
+ if (data->fullscreened) {
+
+ /* Windows has no concept of fullscreen, so to unfullscreen an app you just resize it or move it.
+ * Therefore we need to watch for this behaviour and release fullscreen mode so we can once again
+ * control our position.
+ */
+
+ if (!fromXEvent /* ignore spurious WM changes once we are fullscreened */
+ && !(winpos->flags & (SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE)) /* ignore SWP calls that aren't changing our geometry */
+ && !((newWindowRect.left < 0) && (newWindowRect.top < 0))) /* probably moving us beyond the screen boundaries to hide the borders, ignore */ {
+
+ TRACE("releasing fullscreen for %p\n", winpos->hwnd);
+ toggle_fullscreen( winpos->hwnd );
+ }
+ }
+
/* Fix redundant flags */
if (!fixup_flags( winpos )) return FALSE;
-
- if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
-
+
TRACE("\tcurrent (%ld,%ld)-(%ld,%ld), style %08x\n",
wndPtr->rectWindow.left, wndPtr->rectWindow.top,
wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
@@ -965,15 +1025,16 @@
}
/* Common operations */
+ wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect ); /* FIXME: this should only be called if the size is actually being changed, unless SWP_FRAMECHANGED is set */
- wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect );
-
+ TRACE("after NC_CALCSIZE (%ld,%ld,%ld,%ld)\n", newWindowRect.left, newWindowRect.top, newWindowRect.right, newWindowRect.bottom);
+
if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
{
HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter );
}
-
+
/* Reset active DCEs */
if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
@@ -1039,6 +1100,7 @@
XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
winpos->flags |= SWP_FRAMECHANGED;
}
+
if (winpos->flags & SWP_SHOWWINDOW)
{
set_visible_style( winpos->hwnd, TRUE );
@@ -1177,6 +1239,7 @@
POINT size;
LONG old_style;
WINDOWPLACEMENT wpl;
+ struct x11drv_win_data* data;
TRACE("%p %u\n", hwnd, cmd );
@@ -1195,13 +1258,24 @@
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
+ data = wndPtr->pDriverData;
+
size.x = wndPtr->rectWindow.left;
size.y = wndPtr->rectWindow.top;
+ /* if the window has no caption and is being maximized or restored,
+ this is a good sign we need to (un)fullscreen it */
+ if ((wndPtr->dwStyle & WS_CAPTION) != WS_CAPTION) {
+ if (((cmd == SW_RESTORE) && data->fullscreened) || ((cmd == SW_MAXIMIZE) && !data->fullscreened)) {
+ TRACE("toggling fullscreen due to %s of captionless window %p\n", cmd == SW_MAXIMIZE ? "maximization" : "restoration", hwnd);
+ toggle_fullscreen( hwnd );
+ }
+ }
+
switch( cmd )
{
case SW_MINIMIZE:
- if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
+ if (wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
else wndPtr->flags &= ~WIN_RESTORE_MAX;
WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
@@ -1692,8 +1766,10 @@
/* if nothing changed, don't do anything */
if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
+ TRACE("syncing window pos enter\n");
SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
+ TRACE("syncing window pos leave\n");
}
--- orig/dlls/x11drv/x11drv.h
+++ mod/dlls/x11drv/x11drv.h
@@ -413,6 +413,8 @@
XATOM_DndSelection,
XATOM__MOTIF_WM_HINTS,
XATOM__KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
+ XATOM__NET_WM_STATE,
+ XATOM__NET_WM_STATE_FULLSCREEN,
XATOM__NET_WM_PID,
XATOM__NET_WM_PING,
XATOM__NET_WM_NAME,
@@ -446,6 +448,10 @@
#define x11drv_atom(name) (X11DRV_Atoms[XATOM_##name - FIRST_XATOM])
+#define _NET_WM_STATE_REMOVE 0
+#define _NET_WM_STATE_ADD 1
+#define _NET_WM_STATE_TOGGLE 2
+
/* X11 clipboard driver */
typedef struct tagWINE_CLIPDATA {
@@ -511,6 +517,7 @@
XIC xic; /* X input context */
HBITMAP hWMIconBitmap;
HBITMAP hWMIconMask;
+ BOOL fullscreened; /* does the window have a NETWM fullscreening hint set? */
};
typedef struct x11drv_win_data X11DRV_WND_DATA;
More information about the wine-patches
mailing list