| 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;
|
| }
|
|
|
|
|