Use EWMH Fullscreen hints

   1 
   2 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.
   3 
   4 --- dlls/x11drv/window.c
   5 +++ dlls/x11drv/window.c
   6 @@ -74,6 +74,8 @@
   7      "DndSelection",
   8      "_MOTIF_WM_HINTS",
   9      "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
  10 +    "_NET_WM_STATE",
  11 +    "_NET_WM_STATE_FULLSCREEN",
  12      "_NET_WM_PID",
  13      "_NET_WM_PING",
  14      "_NET_WM_NAME",
  15 @@ -114,6 +116,7 @@
  16  inline static BOOL is_window_managed( WND *win )
  17  {
  18      if (!managed_mode) return FALSE;
  19 +    
  20      /* tray window is always managed */
  21      if (win->dwExStyle & WS_EX_TRAYWINDOW) return TRUE;
  22      /* child windows are not managed */
  23 @@ -126,13 +129,9 @@
  24      if (win->dwStyle & WS_THICKFRAME) return TRUE;
  25      /* application windows are managed */
  26      if (win->dwExStyle & WS_EX_APPWINDOW) return TRUE;
  27 -    /* full-screen popup windows are managed */
  28 -    if ((win->dwStyle & WS_POPUP) && 
  29 -        (win->rectWindow.right-win->rectWindow.left) == screen_width && 
  30 -        (win->rectWindow.bottom-win->rectWindow.top) == screen_height) 
  31 -    {
  32 -        return TRUE;
  33 -    }
  34 +    /* windows with a system menu are managed */
  35 +    if (win->dwStyle & WS_SYSMENU) return TRUE;
  36 +    
  37      /* default: not managed */
  38      return FALSE;
  39  }
  40 @@ -177,7 +176,6 @@
  41      return (CWOverrideRedirect | CWSaveUnder | CWEventMask | CWColormap | CWCursor);
  42  }
  43  
  44 -
  45  /***********************************************************************
  46   *              X11DRV_sync_window_style
  47   *
  48 @@ -354,7 +352,10 @@
  49          size_hints->y = data->whole_rect.top;
  50          size_hints->flags = PWinGravity | PPosition;
  51  
  52 -        if ( !(win->dwStyle & WS_THICKFRAME) )
  53 +        /* we only want to be able to resize windows with WS_THICKFRAME.
  54 +         * in addition, metacity refuses to fullscreen non-resizable windows
  55 +         */
  56 +        if ( !(win->dwStyle & WS_THICKFRAME) && !data->fullscreened)
  57          {
  58              size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
  59              size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
  60 @@ -448,7 +449,7 @@
  61      if (win->dwStyle & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
  62      if (win->dwStyle & WS_SYSMENU)    mwm_hints.functions |= MWM_FUNC_CLOSE;
  63      mwm_hints.decorations = 0;
  64 -    if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) mwm_hints.decorations |= MWM_DECOR_TITLE;
  65 +    if (((win->dwStyle & WS_CAPTION) == WS_CAPTION) && !data->fullscreened) mwm_hints.decorations |= MWM_DECOR_TITLE;
  66      if (win->dwExStyle & WS_EX_DLGMODALFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
  67      else if (win->dwStyle & WS_THICKFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
  68      else if ((win->dwStyle & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
  69 @@ -465,6 +466,15 @@
  70      XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
  71                       XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
  72  
  73 +    /* for windows that are already mapped, toggle_fullscreen sends a message to the WM */        
  74 +    if (data->fullscreened && !(win->dwStyle & WS_VISIBLE)) {
  75 +        Atom newstate = x11drv_atom(_NET_WM_STATE_FULLSCREEN);
  76 +
  77 +        TRACE("setting state to _NET_WM_STATE_FULLSCREEN\n");
  78 +        XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE),
  79 +                         XA_ATOM, 32, PropModeReplace, (unsigned char*)&newstate, 1 );
  80 +    }
  81 +    
  82      wm_hints = XAllocWMHints();
  83      wine_tsx11_unlock();
  84  
  85 @@ -762,6 +772,8 @@
  86      RECT rect;
  87      BOOL is_top_level = is_window_top_level( win );
  88  
  89 +    data->fullscreened = FALSE;
  90 +    
  91      rect = win->rectWindow;
  92      X11DRV_window_to_X_rect( win, &rect );
  93  
  94 --- dlls/x11drv/winpos.c
  95 +++ dlls/x11drv/winpos.c
  96 @@ -3,6 +3,7 @@
  97   *
  98   * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
  99   * Copyright 1995, 1996, 1999 Alex Korobka
 100 + * Copyright 2004 Mike Hearn for CodeWeavers
 101   *
 102   * This library is free software; you can redistribute it and/or
 103   * modify it under the terms of the GNU Lesser General Public
 104 @@ -74,6 +75,46 @@
 105  
 106  
 107  /***********************************************************************
 108 + *     toggle_fullscreen
 109 + *
 110 + * Use the NETWM fullscreening protocol to toggle fullscreened state. This only
 111 + * works for mapped windows.
 112 + */
 113 +static void toggle_fullscreen( HWND hwnd )
 114 +{
 115 +    WND *win = WIN_GetPtr(hwnd);
 116 +    struct x11drv_win_data *data = win->pDriverData;
 117 +    XEvent xev;
 118 +
 119 +    TRACE("hwnd=%p, current=%s\n", hwnd, data->fullscreened ? "true" : "false");
 120 +    data->fullscreened = !data->fullscreened;
 121 +    
 122 +    wine_tsx11_lock();
 123 +
 124 +    X11DRV_set_wm_hints(thread_display(), win);
 125 +
 126 +    if (win->dwStyle & WS_VISIBLE) {
 127 +        TRACE("toggling fullscreen state\n");
 128 +        xev.xclient.type = ClientMessage;
 129 +        xev.xclient.window = data->whole_window;
 130 +        xev.xclient.message_type = x11drv_atom(_NET_WM_STATE);
 131 +        xev.xclient.serial = 0;
 132 +        xev.xclient.display = thread_display();
 133 +        xev.xclient.send_event = True;
 134 +        xev.xclient.format = 32;
 135 +        /* using _NET_WM_STATE_TOGGLE here does not work correctly with some WMs */
 136 +        xev.xclient.data.l[0] = (data->fullscreened ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE);
 137 +        xev.xclient.data.l[1] = x11drv_atom(_NET_WM_STATE_FULLSCREEN);
 138 +        xev.xclient.data.l[2] = 0;
 139 +        XSendEvent(thread_display(), root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
 140 +        TRACE("toggled\n");
 141 +    }
 142 +
 143 +    wine_tsx11_unlock();
 144 +    WIN_ReleasePtr(win);
 145 +}
 146 +
 147 +/***********************************************************************
 148   *     clip_children
 149   *
 150   * Clip all children of a given window out of the visible region
 151 @@ -861,7 +902,7 @@
 152      if (wndPtr == WND_OTHER_PROCESS) return;
 153  
 154      changed = wndPtr->dwStyle ^ oldStyle;
 155 -
 156 +    
 157      if (changed & WS_VISIBLE)
 158      {
 159          if (!IsRectEmpty( &wndPtr->rectWindow ))
 160 @@ -919,12 +960,14 @@
 161      RECT newWindowRect, newClientRect;
 162      RECT oldWindowRect, oldClientRect;
 163      UINT wvrFlags = 0;
 164 -    BOOL bChangePos;
 165 +    BOOL bChangePos, fromXEvent;
 166 +    struct x11drv_win_data *data;
 167  
 168      TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
 169             winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
 170             winpos->cx, winpos->cy, winpos->flags);
 171  
 172 +    fromXEvent = winpos->flags & SWP_WINE_NOHOSTMOVE;
 173      bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
 174      winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
 175  
 176 @@ -949,11 +992,28 @@
 177  
 178      if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
 179  
 180 +    if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
 181 +    data = wndPtr->pDriverData;
 182 +    
 183 +    if (data->fullscreened) {
 184 +        
 185 +        /* Windows has no concept of fullscreen, so to unfullscreen an app you just resize it or move it.
 186 +         * Therefore we need to watch for this behaviour and release fullscreen mode so we can once again
 187 +         * control our position.
 188 +         */
 189 +        
 190 +        if (!fromXEvent /* ignore spurious WM changes once we are fullscreened */
 191 +            && !(winpos->flags & (SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE)) /* ignore SWP calls that aren't changing our geometry */
 192 +            && !((newWindowRect.left < 0) && (newWindowRect.top < 0))) /* probably moving us beyond the screen boundaries to hide the borders, ignore */ {
 193 +            
 194 +            TRACE("releasing fullscreen for %p\n", winpos->hwnd);
 195 +            toggle_fullscreen( winpos->hwnd );
 196 +        }
 197 +    }
 198 +    
 199      /* Fix redundant flags */
 200      if (!fixup_flags( winpos )) return FALSE;
 201 -
 202 -    if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
 203 -
 204 +    
 205      TRACE("\tcurrent (%ld,%ld)-(%ld,%ld), style %08x\n",
 206            wndPtr->rectWindow.left, wndPtr->rectWindow.top,
 207            wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
 208 @@ -965,15 +1025,16 @@
 209      }
 210  
 211      /* Common operations */
 212 +    wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect ); /* FIXME: this should only be called if the size is actually being changed, unless SWP_FRAMECHANGED is set */
 213  
 214 -    wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect );
 215 -
 216 +    TRACE("after NC_CALCSIZE (%ld,%ld,%ld,%ld)\n", newWindowRect.left, newWindowRect.top, newWindowRect.right, newWindowRect.bottom);
 217 +    
 218      if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
 219      {
 220          HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
 221          if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter );
 222      }
 223 -
 224 +        
 225      /* Reset active DCEs */
 226  
 227      if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
 228 @@ -1039,6 +1100,7 @@
 229              XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
 230              winpos->flags |= SWP_FRAMECHANGED;
 231          }
 232 +    
 233          if (winpos->flags & SWP_SHOWWINDOW)
 234          {
 235              set_visible_style( winpos->hwnd, TRUE );
 236 @@ -1177,6 +1239,7 @@
 237      POINT size;
 238      LONG old_style;
 239      WINDOWPLACEMENT wpl;
 240 +    struct x11drv_win_data* data;
 241  
 242      TRACE("%p %u\n", hwnd, cmd );
 243  
 244 @@ -1195,13 +1258,24 @@
 245  
 246      if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
 247  
 248 +    data = wndPtr->pDriverData;
 249 +    
 250      size.x = wndPtr->rectWindow.left;
 251      size.y = wndPtr->rectWindow.top;
 252  
 253 +    /* if the window has no caption and is being maximized or restored,
 254 +       this is a good sign we need to (un)fullscreen it */
 255 +    if ((wndPtr->dwStyle & WS_CAPTION) != WS_CAPTION) {
 256 +        if (((cmd == SW_RESTORE) && data->fullscreened) || ((cmd == SW_MAXIMIZE) && !data->fullscreened)) {
 257 +            TRACE("toggling fullscreen due to %s of captionless window %p\n", cmd == SW_MAXIMIZE ? "maximization" : "restoration", hwnd);
 258 +            toggle_fullscreen( hwnd );
 259 +        }
 260 +    }
 261 +    
 262      switch( cmd )
 263      {
 264      case SW_MINIMIZE:
 265 -        if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
 266 +        if (wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
 267          else wndPtr->flags &= ~WIN_RESTORE_MAX;
 268  
 269          WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
 270 @@ -1692,8 +1766,10 @@
 271      /* if nothing changed, don't do anything */
 272      if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
 273  
 274 +    TRACE("syncing window pos enter\n");
 275      SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
 276                    winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
 277 +    TRACE("syncing window pos leave\n");
 278  }
 279  
 280  
 281 --- dlls/x11drv/x11drv.h
 282 +++ dlls/x11drv/x11drv.h
 283 @@ -413,6 +413,8 @@
 284      XATOM_DndSelection,
 285      XATOM__MOTIF_WM_HINTS,
 286      XATOM__KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
 287 +    XATOM__NET_WM_STATE,
 288 +    XATOM__NET_WM_STATE_FULLSCREEN,
 289      XATOM__NET_WM_PID,
 290      XATOM__NET_WM_PING,
 291      XATOM__NET_WM_NAME,
 292 @@ -446,6 +448,10 @@
 293  
 294  #define x11drv_atom(name) (X11DRV_Atoms[XATOM_##name - FIRST_XATOM])
 295  
 296 +#define _NET_WM_STATE_REMOVE 0
 297 +#define _NET_WM_STATE_ADD 1
 298 +#define _NET_WM_STATE_TOGGLE 2
 299 +
 300  /* X11 clipboard driver */
 301  
 302  typedef struct tagWINE_CLIPDATA {
 303 @@ -511,6 +517,7 @@
 304      XIC     xic;            /* X input context */
 305      HBITMAP hWMIconBitmap;
 306      HBITMAP hWMIconMask;
 307 +    BOOL    fullscreened;   /* does the window have a NETWM fullscreening hint set? */
 308  };
 309  
 310  typedef struct x11drv_win_data X11DRV_WND_DATA;
 311 

Use EWMH Fullscreen hints (last edited 2008-05-03 00:25:37 by nathan.n)