| Index: chrome/views/window/window_win.cc
 | 
| ===================================================================
 | 
| --- chrome/views/window/window_win.cc	(revision 13759)
 | 
| +++ chrome/views/window/window_win.cc	(working copy)
 | 
| @@ -25,6 +25,28 @@
 | 
|  #include "chrome/views/window/window_delegate.h"
 | 
|  #include "grit/generated_resources.h"
 | 
|  
 | 
| +namespace {
 | 
| +
 | 
| +bool GetMonitorAndRects(const RECT& rect,
 | 
| +                        HMONITOR* monitor,
 | 
| +                        gfx::Rect* monitor_rect,
 | 
| +                        gfx::Rect* work_area) {
 | 
| +  DCHECK(monitor);
 | 
| +  DCHECK(monitor_rect);
 | 
| +  DCHECK(work_area);
 | 
| +  *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
 | 
| +  if (!*monitor)
 | 
| +    return false;
 | 
| +  MONITORINFO monitor_info = { 0 };
 | 
| +  monitor_info.cbSize = sizeof(monitor_info);
 | 
| +  GetMonitorInfo(*monitor, &monitor_info);
 | 
| +  *monitor_rect = monitor_info.rcMonitor;
 | 
| +  *work_area = monitor_info.rcWork;
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
|  namespace views {
 | 
|  
 | 
|  // A scoping class that prevents a window from being able to redraw in response
 | 
| @@ -96,6 +118,19 @@
 | 
|    return bounds;
 | 
|  }
 | 
|  
 | 
| +gfx::Rect WindowWin::GetNormalBounds() const {
 | 
| +  // If we're in fullscreen mode, we've changed the normal bounds to the monitor
 | 
| +  // rect, so return the saved bounds instead.
 | 
| +  if (IsFullscreen())
 | 
| +    return gfx::Rect(saved_window_info_.window_rect);
 | 
| +
 | 
| +  WINDOWPLACEMENT wp;
 | 
| +  wp.length = sizeof(wp);
 | 
| +  const bool ret = !!GetWindowPlacement(GetNativeView(), &wp);
 | 
| +  DCHECK(ret);
 | 
| +  return gfx::Rect(wp.rcNormalPosition);
 | 
| +}
 | 
| +
 | 
|  void WindowWin::SetBounds(const gfx::Rect& bounds) {
 | 
|    SetBounds(bounds, NULL);
 | 
|  }
 | 
| @@ -138,6 +173,18 @@
 | 
|      SendMessage(GetNativeView(), WM_SYSCOMMAND, command, 0);
 | 
|  }
 | 
|  
 | 
| +void WindowWin::PushForceHidden() {
 | 
| +  if (force_hidden_count_++ == 0)
 | 
| +    Hide();
 | 
| +}
 | 
| +
 | 
| +void WindowWin::PopForceHidden() {
 | 
| +  if (--force_hidden_count_ <= 0) {
 | 
| +    force_hidden_count_ = 0;
 | 
| +    ShowWindow(SW_SHOW);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  // static
 | 
|  int Window::GetLocalizedContentsWidth(int col_resource_id) {
 | 
|    double chars = _wtof(l10n_util::GetString(col_resource_id).c_str());
 | 
| @@ -235,6 +282,66 @@
 | 
|    return !!::IsIconic(GetNativeView());
 | 
|  }
 | 
|  
 | 
| +void WindowWin::SetFullscreen(bool fullscreen) {
 | 
| +  if (fullscreen_ == fullscreen)
 | 
| +    return;  // Nothing to do.
 | 
| +
 | 
| +  // Toggle fullscreen mode.
 | 
| +  fullscreen_ = fullscreen;
 | 
| +
 | 
| +  // Reduce jankiness during the following position changes by hiding the window
 | 
| +  // until it's in the final position.
 | 
| +  PushForceHidden();
 | 
| +
 | 
| +  // Size/position/style window appropriately.
 | 
| +  HWND hwnd = GetNativeView();
 | 
| +  if (fullscreen_) {
 | 
| +    // Save current window information.  We force the window into restored mode
 | 
| +    // before going fullscreen because Windows doesn't seem to hide the
 | 
| +    // taskbar if the window is in the maximized state.
 | 
| +    saved_window_info_.maximized = IsMaximized();
 | 
| +    if (saved_window_info_.maximized)
 | 
| +      ExecuteSystemMenuCommand(SC_RESTORE);
 | 
| +    saved_window_info_.style = GetWindowLong(GWL_STYLE);
 | 
| +    saved_window_info_.ex_style = GetWindowLong(GWL_EXSTYLE);
 | 
| +    GetWindowRect(&saved_window_info_.window_rect);
 | 
| +
 | 
| +    // Set new window style and size.
 | 
| +    MONITORINFO monitor_info;
 | 
| +    monitor_info.cbSize = sizeof(monitor_info);
 | 
| +    GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
 | 
| +                   &monitor_info);
 | 
| +    gfx::Rect monitor_rect(monitor_info.rcMonitor);
 | 
| +    SetWindowLong(GWL_STYLE,
 | 
| +                  saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
 | 
| +    SetWindowLong(GWL_EXSTYLE,
 | 
| +                  saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME |
 | 
| +                  WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
 | 
| +    SetWindowPos(NULL, monitor_rect.x(), monitor_rect.y(),
 | 
| +                 monitor_rect.width(), monitor_rect.height(),
 | 
| +                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
 | 
| +  } else {
 | 
| +    // Reset original window style and size.  The multiple window size/moves
 | 
| +    // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
 | 
| +    // repainted.  Better-looking methods welcome.
 | 
| +    gfx::Rect new_rect(saved_window_info_.window_rect);
 | 
| +    SetWindowLong(GWL_STYLE, saved_window_info_.style);
 | 
| +    SetWindowLong(GWL_EXSTYLE, saved_window_info_.ex_style);
 | 
| +    SetWindowPos(NULL, new_rect.x(), new_rect.y(), new_rect.width(),
 | 
| +                 new_rect.height(),
 | 
| +                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
 | 
| +    if (saved_window_info_.maximized)
 | 
| +      ExecuteSystemMenuCommand(SC_MAXIMIZE);
 | 
| +  }
 | 
| +
 | 
| +  // Undo our anti-jankiness hacks.
 | 
| +  PopForceHidden();
 | 
| +}
 | 
| +
 | 
| +bool WindowWin::IsFullscreen() const {
 | 
| +  return fullscreen_;
 | 
| +}
 | 
| +
 | 
|  void WindowWin::EnableClose(bool enable) {
 | 
|    // If the native frame is rendering its own close button, ask it to disable.
 | 
|    non_client_view_->EnableClose(enable);
 | 
| @@ -348,13 +455,17 @@
 | 
|        is_modal_(false),
 | 
|        restored_enabled_(false),
 | 
|        is_always_on_top_(false),
 | 
| +      fullscreen_(false),
 | 
|        window_closed_(false),
 | 
|        disable_inactive_rendering_(false),
 | 
|        is_active_(false),
 | 
|        lock_updates_(false),
 | 
|        saved_window_style_(0),
 | 
|        saved_maximized_state_(0),
 | 
| -      force_hidden_(false) {
 | 
| +      ignore_window_pos_changes_(false),
 | 
| +      ignore_pos_changes_factory_(this),
 | 
| +      force_hidden_count_(0),
 | 
| +      last_monitor_(NULL) {
 | 
|    InitClass();
 | 
|    DCHECK(window_delegate_);
 | 
|    window_delegate_->window_.reset(this);
 | 
| @@ -393,6 +504,9 @@
 | 
|    SetInitialBounds(bounds);
 | 
|    InitAlwaysOnTopState();
 | 
|  
 | 
| +  GetMonitorAndRects(bounds.ToRECT(), &last_monitor_, &last_monitor_rect_,
 | 
| +                     &last_work_area_);
 | 
| +
 | 
|    if (!IsAppWindow()) {
 | 
|      notification_registrar_.Add(
 | 
|          this,
 | 
| @@ -497,9 +611,9 @@
 | 
|    // Important step: restore the window first, since our hiding hack doesn't
 | 
|    // work for maximized windows! We tell the frame not to allow itself to be
 | 
|    // made visible though, which removes the brief flicker.
 | 
| -  force_hidden_ = true;
 | 
| +  ++force_hidden_count_;
 | 
|    ::ShowWindow(GetNativeView(), SW_RESTORE);
 | 
| -  force_hidden_ = false;
 | 
| +  --force_hidden_count_;
 | 
|  
 | 
|    // We respond to this in response to WM_DWMCOMPOSITIONCHANGED since that is
 | 
|    // the only thing we care about - we don't actually respond to WM_THEMECHANGED
 | 
| @@ -631,7 +745,7 @@
 | 
|      // treated as a "fullscreen app", which would cause the taskbars to
 | 
|      // disappear.
 | 
|      HMONITOR monitor = MonitorFromWindow(GetNativeView(),
 | 
| -                                         MONITOR_DEFAULTTONEAREST);
 | 
| +                                         MONITOR_DEFAULTTONULL);
 | 
|      if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_LEFT, monitor))
 | 
|        client_rect->left += win_util::kAutoHideTaskbarThicknessPx;
 | 
|      if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_TOP, monitor))
 | 
| @@ -905,6 +1019,18 @@
 | 
|                         reinterpret_cast<LPARAM>(text));
 | 
|  }
 | 
|  
 | 
| +void WindowWin::OnSettingChange(UINT flags, const wchar_t* section) {
 | 
| +  if (!GetParent() && (flags == SPI_SETWORKAREA)) {
 | 
| +    // Fire a dummy SetWindowPos() call, so we'll trip the code in
 | 
| +    // OnWindowPosChanging() below that notices work area changes.
 | 
| +    ::SetWindowPos(GetNativeView(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
 | 
| +        SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
 | 
| +    SetMsgHandled(TRUE);
 | 
| +  } else {
 | 
| +    WidgetWin::OnSettingChange(flags, section);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  void WindowWin::OnSize(UINT size_param, const CSize& new_size) {
 | 
|    // Don't no-op if the new_size matches current size. If our normal bounds
 | 
|    // and maximized bounds are the same, then we need to layout (because we
 | 
| @@ -971,11 +1097,82 @@
 | 
|  }
 | 
|  
 | 
|  void WindowWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
 | 
| -  if (force_hidden_) {
 | 
| +  if (force_hidden_count_) {
 | 
|      // Prevent the window from being made visible if we've been asked to do so.
 | 
|      // See comment in header as to why we might want this.
 | 
|      window_pos->flags &= ~SWP_SHOWWINDOW;
 | 
|    }
 | 
| +
 | 
| +  if (ignore_window_pos_changes_) {
 | 
| +    // If somebody's trying to toggle our visibility, change the nonclient area,
 | 
| +    // change our Z-order, or activate us, we should probably let it go through.
 | 
| +    if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) |
 | 
| +        SWP_FRAMECHANGED)) &&
 | 
| +        (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) {
 | 
| +      // Just sizing/moving the window; ignore.
 | 
| +      window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW;
 | 
| +      window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW);
 | 
| +    }
 | 
| +  } else if (!GetParent()) {
 | 
| +    CRect window_rect;
 | 
| +    HMONITOR monitor;
 | 
| +    gfx::Rect monitor_rect, work_area;
 | 
| +    if (GetWindowRect(&window_rect) &&
 | 
| +        GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) {
 | 
| +      if (monitor && (monitor == last_monitor_) &&
 | 
| +          (IsFullscreen() || ((monitor_rect == last_monitor_rect_) &&
 | 
| +                              (work_area != last_work_area_)))) {
 | 
| +        // A rect for the monitor we're on changed.  Normally Windows notifies
 | 
| +        // us about this (and thus we're reaching here due to the SetWindowPos()
 | 
| +        // call in OnSettingChange() above), but with some software (e.g.
 | 
| +        // nVidia's nView desktop manager) the work area can change asynchronous
 | 
| +        // to any notification, and we're just sent a SetWindowPos() call with a
 | 
| +        // new (frequently incorrect) position/size.  In either case, the best
 | 
| +        // response is to throw away the existing position/size information in
 | 
| +        // |window_pos| and recalculate it based on the old window coordinates,
 | 
| +        // adjusted for the change in the work area (or, for fullscreen windows,
 | 
| +        // to just set it to the monitor rect).
 | 
| +        if (IsFullscreen()) {
 | 
| +          window_pos->x = monitor_rect.x();
 | 
| +          window_pos->y = monitor_rect.y();
 | 
| +          window_pos->cx = monitor_rect.width();
 | 
| +          window_pos->cy = monitor_rect.height();
 | 
| +        } else if (IsZoomed()) {
 | 
| +          window_pos->x =
 | 
| +              window_rect.left + work_area.x() - last_work_area_.x();
 | 
| +          window_pos->y = window_rect.top + work_area.y() - last_work_area_.y();
 | 
| +          window_pos->cx = window_rect.Width() + work_area.width() -
 | 
| +              last_work_area_.width();
 | 
| +          window_pos->cy = window_rect.Height() + work_area.height() -
 | 
| +              last_work_area_.height();
 | 
| +        } else {
 | 
| +          gfx::Rect window_gfx_rect(window_rect);
 | 
| +          gfx::Rect new_window_rect = window_gfx_rect.AdjustToFit(work_area);
 | 
| +          window_pos->x = new_window_rect.x();
 | 
| +          window_pos->y = new_window_rect.y();
 | 
| +          window_pos->cx = new_window_rect.width();
 | 
| +          window_pos->cy = new_window_rect.height();
 | 
| +        }
 | 
| +        // WARNING!  Don't set SWP_FRAMECHANGED here, it breaks moving the child
 | 
| +        // HWNDs for some reason.
 | 
| +        window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
 | 
| +        window_pos->flags |= SWP_NOCOPYBITS;
 | 
| +
 | 
| +        // Now ignore all immediately-following SetWindowPos() changes.  Windows
 | 
| +        // likes to (incorrectly) recalculate what our position/size should be
 | 
| +        // and send us further updates.
 | 
| +        ignore_window_pos_changes_ = true;
 | 
| +        DCHECK(ignore_pos_changes_factory_.empty());
 | 
| +        MessageLoop::current()->PostTask(FROM_HERE,
 | 
| +            ignore_pos_changes_factory_.NewRunnableMethod(
 | 
| +            &WindowWin::StopIgnoringPosChanges));
 | 
| +      }
 | 
| +      last_monitor_ = monitor;
 | 
| +      last_monitor_rect_ = monitor_rect;
 | 
| +      last_work_area_ = work_area;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|    WidgetWin::OnWindowPosChanging(window_pos);
 | 
|  }
 | 
|  
 | 
| @@ -1167,12 +1364,12 @@
 | 
|  
 | 
|  void WindowWin::LockUpdates() {
 | 
|    lock_updates_ = true;
 | 
| -  saved_window_style_ = GetWindowLong(GetNativeView(), GWL_STYLE);
 | 
| -  SetWindowLong(GetNativeView(), GWL_STYLE, saved_window_style_ & ~WS_VISIBLE);
 | 
| +  saved_window_style_ = GetWindowLong(GWL_STYLE);
 | 
| +  SetWindowLong(GWL_STYLE, saved_window_style_ & ~WS_VISIBLE);
 | 
|  }
 | 
|  
 | 
|  void WindowWin::UnlockUpdates() {
 | 
| -  SetWindowLong(GetNativeView(), GWL_STYLE, saved_window_style_);
 | 
| +  SetWindowLong(GWL_STYLE, saved_window_style_);
 | 
|    lock_updates_ = false;
 | 
|  }
 | 
|  
 | 
| 
 |