Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6938)

Unified Diff: chrome/views/window/window_win.cc

Issue 78002: Reorganize fullscreen mode handling. Now nearly everything is in WindowWin. ... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/views/window/window_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
« no previous file with comments | « chrome/views/window/window_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698