summaryrefslogtreecommitdiffstats
path: root/chrome/views/window.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/views/window.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/views/window.cc')
-rw-r--r--chrome/views/window.cc660
1 files changed, 660 insertions, 0 deletions
diff --git a/chrome/views/window.cc b/chrome/views/window.cc
new file mode 100644
index 0000000..24b4925
--- /dev/null
+++ b/chrome/views/window.cc
@@ -0,0 +1,660 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/views/window.h"
+
+#include "chrome/app/chrome_dll_resource.h"
+// TODO(beng): some day make this unfortunate dependency not exist.
+#include "chrome/browser/browser_list.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/win_util.h"
+#include "chrome/views/client_view.h"
+#include "chrome/views/custom_frame_window.h"
+#include "chrome/views/window_delegate.h"
+
+#include "generated_resources.h"
+
+namespace ChromeViews {
+
+// static
+HCURSOR Window::nwse_cursor_ = NULL;
+
+// If the hung renderer warning doesn't fit on screen, the amount of padding to
+// be left between the edge of the window and the edge of the nearest monitor,
+// after the window is nudged back on screen. Pixels.
+static const int kMonitorEdgePadding = 10;
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, public:
+
+Window::Window()
+ : HWNDViewContainer(),
+ focus_on_creation_(true),
+ client_view_(NULL),
+ window_delegate_(NULL),
+ owning_hwnd_(NULL),
+ minimum_size_(100, 100),
+ is_modal_(false),
+ restored_enabled_(false),
+ is_always_on_top_(false),
+ use_client_view_(true),
+ accepted_(false),
+ window_closed_(false) {
+ InitClass();
+ // Initialize these values to 0 so that subclasses can override the default
+ // behavior before calling Init.
+ set_window_style(0);
+ set_window_ex_style(0);
+ BrowserList::AddDependentWindow(this);
+}
+
+Window::~Window() {
+ BrowserList::RemoveDependentWindow(this);
+}
+
+// static
+Window* Window::CreateChromeWindow(HWND parent,
+ const gfx::Rect& bounds,
+ View* contents_view,
+ WindowDelegate* window_delegate) {
+ if (win_util::ShouldUseVistaFrame()) {
+ Window* window = new Window;
+ window->Init(parent, bounds, contents_view, window_delegate);
+ return window;
+ }
+ CustomFrameWindow* window = new CustomFrameWindow;
+ window->Init(parent, bounds, contents_view, window_delegate);
+ return window;
+}
+
+void Window::Init(HWND parent,
+ const gfx::Rect& bounds,
+ View* contents_view,
+ WindowDelegate* window_delegate) {
+ window_delegate_ = window_delegate;
+ // We need to save the parent window, since later calls to GetParent() will
+ // return NULL.
+ owning_hwnd_ = parent;
+ // We call this after initializing our members since our implementations of
+ // assorted HWNDViewContainer functions may be called during initialization.
+ if (window_delegate_) {
+ is_modal_ = window_delegate_->IsModal();
+ if (is_modal_)
+ BecomeModal();
+ is_always_on_top_ = window_delegate_->IsAlwaysOnTop();
+ }
+
+ if (window_style() == 0)
+ set_window_style(CalculateWindowStyle());
+ if (window_ex_style() == 0)
+ set_window_ex_style(CalculateWindowExStyle());
+
+ // A child window never owns its own focus manager, it uses the one
+ // associated with the root of the window tree...
+ if (use_client_view_) {
+ client_view_ = new ClientView(this, contents_view);
+ // A Window almost always owns its own focus manager, even if it's a child
+ // window. File a bug if you find a circumstance where this isn't the case
+ // and we can adjust this API. Note that if this is not the case, you'll
+ // also have to change SetInitialFocus() as it relies on the window's focus
+ // manager.
+ HWNDViewContainer::Init(parent, bounds, client_view_, true);
+ } else {
+ HWNDViewContainer::Init(parent, bounds, contents_view, true);
+ }
+
+ if (window_delegate_) {
+ std::wstring window_title = window_delegate_->GetWindowTitle();
+ SetWindowText(GetHWND(), window_title.c_str());
+ }
+
+ win_util::SetWindowUserData(GetHWND(), this);
+
+ // Restore the window's placement from the controller.
+ CRect saved_bounds(0, 0, 0, 0);
+ bool maximized = false;
+ if (window_delegate_ &&
+ window_delegate_->RestoreWindowPosition(&saved_bounds,
+ &maximized,
+ &is_always_on_top_)) {
+ // Make sure the bounds are at least the minimum size.
+ if (saved_bounds.Width() < minimum_size_.cx) {
+ saved_bounds.SetRect(saved_bounds.left, saved_bounds.top,
+ saved_bounds.right + minimum_size_.cx -
+ saved_bounds.Width(),
+ saved_bounds.bottom);
+ }
+
+ if (saved_bounds.Height() < minimum_size_.cy) {
+ saved_bounds.SetRect(saved_bounds.left, saved_bounds.top,
+ saved_bounds.right,
+ saved_bounds.bottom + minimum_size_.cy -
+ saved_bounds.Height());
+ }
+
+ WINDOWPLACEMENT placement = {0};
+ placement.length = sizeof(WINDOWPLACEMENT);
+ placement.rcNormalPosition = saved_bounds;
+ if (maximized)
+ placement.showCmd = SW_SHOWMAXIMIZED;
+ ::SetWindowPlacement(GetHWND(), &placement);
+
+ if (is_always_on_top_ != window_delegate_->IsAlwaysOnTop())
+ AlwaysOnTopChanged();
+ } else if (bounds.IsEmpty()) {
+ // Size the window to the content and center over the parent.
+ SizeWindowToDefault();
+ }
+
+ if (window_delegate_ && window_delegate->HasAlwaysOnTopMenu())
+ AddAlwaysOnTopSystemMenuItem();
+}
+
+gfx::Size Window::CalculateWindowSizeForClientSize(
+ const gfx::Size& client_size) const {
+ RECT r = { 0, 0, client_size.width(), client_size.height() };
+ ::AdjustWindowRectEx(&r, window_style(), FALSE, window_ex_style());
+ return gfx::Size(r.right - r.left, r.bottom - r.top);
+}
+
+gfx::Size Window::CalculateMaximumSize() const {
+ // If this is a top level window, the maximum size is the size of the working
+ // rect of the display the window is on, less padding. If this is a child
+ // (constrained) window, the maximum size of this Window are the bounds of the
+ // parent window, less padding.
+ DCHECK(GetHWND()) << "Cannot calculate maximum size before Init() is called";
+ gfx::Rect working_rect;
+ HWND parent_hwnd = ::GetParent(GetHWND());
+ if (parent_hwnd) {
+ RECT parent_rect;
+ ::GetClientRect(parent_hwnd, &parent_rect);
+ working_rect = parent_rect;
+ } else {
+ HMONITOR current_monitor =
+ ::MonitorFromWindow(GetHWND(), MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ ::GetMonitorInfo(current_monitor, &mi);
+ working_rect = mi.rcWork;
+ }
+ working_rect.Inset(kMonitorEdgePadding, kMonitorEdgePadding);
+ return working_rect.size();
+}
+
+void Window::Show() {
+ ShowWindow(SW_SHOW);
+ SetInitialFocus();
+}
+
+void Window::Activate() {
+ ::SetWindowPos(GetHWND(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+}
+
+void Window::SetBounds(const gfx::Rect& bounds) {
+ SetBounds(bounds, NULL);
+}
+
+void Window::SetBounds(const gfx::Rect& bounds, HWND other_hwnd) {
+ win_util::SetChildBounds(GetHWND(), GetParent(), other_hwnd, bounds,
+ kMonitorEdgePadding, 0);
+}
+
+void Window::Close() {
+ if (window_closed_) {
+ // It appears we can hit this code path if you close a modal dialog then
+ // close the last browser before the destructor is hit, which triggers
+ // invoking Close again. I'm short circuiting this code path to avoid
+ // calling into the delegate twice, which is problematic.
+ return;
+ }
+
+ bool can_close = true;
+ // Ask the delegate if we're allowed to close. The user may not have left the
+ // window in a state where this is allowable (e.g. unsaved work). Also, don't
+ // call Cancel on the delegate if we've already been accepted and are in the
+ // process of being closed. Furthermore, if we have only an OK button, but no
+ // Cancel button, and we're closing without being accepted, call Accept to
+ // see if we should close.
+ if (!accepted_ && window_delegate_) {
+ DialogDelegate* dd = window_delegate_->AsDialogDelegate();
+ if (dd) {
+ int buttons = dd->GetDialogButtons();
+ if (buttons & DialogDelegate::DIALOGBUTTON_CANCEL)
+ can_close = dd->Cancel();
+ else if (buttons & DialogDelegate::DIALOGBUTTON_OK)
+ can_close = dd->Accept(true);
+ }
+ }
+ if (can_close) {
+ SaveWindowPosition();
+ RestoreEnabledIfNecessary();
+ HWNDViewContainer::Close();
+ // If the user activates another app after opening us, then comes back and
+ // closes us, we want our owner to gain activation. But only if the owner
+ // is visible. If we don't manually force that here, the other app will
+ // regain activation instead.
+ if (owning_hwnd_ && GetHWND() == GetForegroundWindow() &&
+ IsWindowVisible(owning_hwnd_)) {
+ SetForegroundWindow(owning_hwnd_);
+ }
+ window_closed_ = true;
+ }
+}
+
+bool Window::IsMaximized() const {
+ return !!::IsZoomed(GetHWND());
+}
+
+bool Window::IsMinimized() const {
+ return !!::IsIconic(GetHWND());
+}
+
+void Window::EnableClose(bool enable) {
+ EnableMenuItem(::GetSystemMenu(GetHWND(), false),
+ SC_CLOSE,
+ enable ? MF_ENABLED : MF_GRAYED);
+
+ // Let the window know the frame changed.
+ SetWindowPos(NULL, 0, 0, 0, 0,
+ SWP_FRAMECHANGED |
+ SWP_NOACTIVATE |
+ SWP_NOCOPYBITS |
+ SWP_NOMOVE |
+ SWP_NOOWNERZORDER |
+ SWP_NOREPOSITION |
+ SWP_NOSENDCHANGING |
+ SWP_NOSIZE |
+ SWP_NOZORDER);
+}
+
+void Window::UpdateDialogButtons() {
+ if (client_view_)
+ client_view_->UpdateDialogButtons();
+}
+
+void Window::AcceptWindow() {
+ accepted_ = true;
+ if (window_delegate_) {
+ DialogDelegate* dd = window_delegate_->AsDialogDelegate();
+ if (dd)
+ accepted_ = dd->Accept(false);
+ }
+ if (accepted_)
+ Close();
+}
+
+void Window::CancelWindow() {
+ // Call the standard Close handler, which checks with the delegate before
+ // proceeding. This checking _isn't_ done here, but in the WM_CLOSE handler,
+ // so that the close box on the window also shares this code path.
+ Close();
+}
+
+void Window::UpdateWindowTitle() {
+ if (window_delegate_) {
+ std::wstring window_title = window_delegate_->GetWindowTitle();
+ SetWindowText(GetHWND(), window_title.c_str());
+ }
+}
+
+// static
+bool Window::SaveWindowPositionToPrefService(PrefService* pref_service,
+ const std::wstring& entry,
+ const CRect& bounds,
+ bool maximized,
+ bool always_on_top) {
+ DCHECK(pref_service);
+ DictionaryValue* win_pref = pref_service->GetMutableDictionary(entry.c_str());
+ DCHECK(win_pref);
+
+ win_pref->SetInteger(L"left", bounds.left);
+ win_pref->SetInteger(L"top", bounds.top);
+ win_pref->SetInteger(L"right", bounds.right);
+ win_pref->SetInteger(L"bottom", bounds.bottom);
+ win_pref->SetBoolean(L"maximized", maximized);
+ win_pref->SetBoolean(L"always_on_top", always_on_top);
+ return true;
+}
+
+// static
+bool Window::RestoreWindowPositionFromPrefService(PrefService* pref_service,
+ const std::wstring& entry,
+ CRect* bounds,
+ bool* maximized,
+ bool* always_on_top) {
+ DCHECK(pref_service);
+ DCHECK(bounds);
+ DCHECK(maximized);
+ DCHECK(always_on_top);
+
+ const DictionaryValue* dictionary = pref_service->GetDictionary(entry.c_str());
+ if (!dictionary)
+ return false;
+
+ int left, top, right, bottom;
+ bool temp_maximized, temp_always_on_top;
+ if (!dictionary || !dictionary->GetInteger(L"left", &left) ||
+ !dictionary->GetInteger(L"top", &top) ||
+ !dictionary->GetInteger(L"right", &right) ||
+ !dictionary->GetInteger(L"bottom", &bottom) ||
+ !dictionary->GetBoolean(L"maximized", &temp_maximized) ||
+ !dictionary->GetBoolean(L"always_on_top", &temp_always_on_top))
+ return false;
+
+ bounds->SetRect(left, top, right, bottom);
+ *maximized = temp_maximized;
+ *always_on_top = temp_always_on_top;
+ return true;
+}
+
+// static
+gfx::Size Window::GetLocalizedContentsSize(int col_resource_id,
+ int row_resource_id) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ ChromeFont font = rb.GetFont(ResourceBundle::BaseFont);
+
+ double chars = _wtof(l10n_util::GetString(col_resource_id).c_str());
+ double lines = _wtof(l10n_util::GetString(row_resource_id).c_str());
+
+ int width = static_cast<int>(font.ave_char_width() * chars);
+ int height = static_cast<int>(font.height() * lines);
+
+ DCHECK(width > 0 && height > 0);
+
+ return gfx::Size(width, height);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, protected:
+
+void Window::SizeWindowToDefault() {
+ if (client_view_) {
+ CSize pref(0, 0);
+ client_view_->GetPreferredSize(&pref);
+ DCHECK(pref.cx > 0 && pref.cy > 0);
+ // CenterAndSizeWindow adjusts the window size to accommodate the non-client
+ // area.
+ win_util::CenterAndSizeWindow(owning_window(), GetHWND(), pref, true);
+ }
+}
+
+void Window::SetInitialFocus() {
+ if (!focus_on_creation_)
+ return;
+
+ bool focus_set = false;
+ if (window_delegate_) {
+ ChromeViews::View* v = window_delegate_->GetInitiallyFocusedView();
+ // For dialogs, try to focus either the OK or Cancel buttons if any.
+ if (!v && window_delegate_->AsDialogDelegate() && client_view_) {
+ if (client_view_->ok_button())
+ v = client_view_->ok_button();
+ else if (client_view_->cancel_button())
+ v = client_view_->cancel_button();
+ }
+ if (v) {
+ focus_set = true;
+ // In order to make that view the initially focused one, we make it the
+ // focused view on the focus manager and we store the focused view.
+ // When the window is activated, the focus manager will restore the
+ // stored focused view.
+ FocusManager* focus_manager = FocusManager::GetFocusManager(GetHWND());
+ DCHECK(focus_manager);
+ focus_manager->SetFocusedView(v);
+ focus_manager->StoreFocusedView();
+ }
+ }
+
+ if (!focus_set && focus_on_creation_) {
+ // The window does not get keyboard messages unless we focus it, not sure
+ // why.
+ SetFocus(GetHWND());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, HWNDViewContainer overrides:
+
+void Window::OnActivate(UINT action, BOOL minimized, HWND window) {
+ if (action == WA_INACTIVE)
+ SaveWindowPosition();
+}
+
+void Window::OnCommand(UINT notification_code, int command_id, HWND window) {
+ if (window_delegate_)
+ window_delegate_->ExecuteWindowsCommand(command_id);
+}
+
+void Window::OnDestroy() {
+ if (window_delegate_) {
+ window_delegate_->WindowClosing();
+ window_delegate_ = NULL;
+ }
+ RestoreEnabledIfNecessary();
+ HWNDViewContainer::OnDestroy();
+}
+
+LRESULT Window::OnEraseBkgnd(HDC dc) {
+ SetMsgHandled(TRUE);
+ return 1;
+}
+
+LRESULT Window::OnNCHitTest(const CPoint& point) {
+ // We paint the size box over the content area sometimes... check to see if
+ // the mouse is over it...
+ CPoint temp = point;
+ MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1);
+ if (client_view_ && client_view_->PointIsInSizeBox(gfx::Point(temp)))
+ return HTBOTTOMRIGHT;
+
+ // Otherwise, we let Windows do all the native frame non-client handling for
+ // us.
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT Window::OnSetCursor(HWND window, UINT hittest_code, UINT message) {
+ if (hittest_code == HTBOTTOMRIGHT) {
+ // If the mouse was over the resize gripper, make sure the right cursor is
+ // supplied...
+ SetCursor(nwse_cursor_);
+ return TRUE;
+ }
+ // Otherwise just let Windows do the rest.
+ SetMsgHandled(FALSE);
+ return TRUE;
+}
+
+void Window::OnSize(UINT size_param, const CSize& new_size) {
+ if (root_view_->GetWidth() == new_size.cx &&
+ root_view_->GetHeight() == new_size.cy)
+ return;
+
+ SaveWindowPosition();
+ ChangeSize(size_param, new_size);
+ RedrawWindow(GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
+}
+
+void Window::OnSysCommand(UINT notification_code, CPoint click) {
+ if (notification_code == IDC_ALWAYS_ON_TOP) {
+ is_always_on_top_ = !is_always_on_top_;
+
+ // Change the menu check state.
+ HMENU system_menu = ::GetSystemMenu(GetHWND(), FALSE);
+ MENUITEMINFO menu_info;
+ memset(&menu_info, 0, sizeof(MENUITEMINFO));
+ menu_info.cbSize = sizeof(MENUITEMINFO);
+ BOOL r = ::GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP,
+ FALSE, &menu_info);
+ DCHECK(r);
+ menu_info.fMask = MIIM_STATE;
+ if (is_always_on_top_)
+ menu_info.fState = MFS_CHECKED;
+ r = ::SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info);
+
+ // Now change the actual window's behavior.
+ AlwaysOnTopChanged();
+ } else {
+ // Use the default implementation for any other command.
+ DefWindowProc(GetHWND(), WM_SYSCOMMAND, notification_code,
+ MAKELPARAM(click.y, click.x));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, private:
+
+void Window::BecomeModal() {
+ // We implement modality by crawling up the hierarchy of windows starting
+ // at the owner, disabling all of them so that they don't receive input
+ // messages.
+ DCHECK(owning_hwnd_) << "Can't create a modal dialog without an owner";
+ HWND start = owning_hwnd_;
+ while (start != NULL) {
+ ::EnableWindow(start, FALSE);
+ start = ::GetParent(start);
+ }
+}
+
+void Window::AddAlwaysOnTopSystemMenuItem() {
+ // The Win32 API requires that we own the text.
+ always_on_top_menu_text_ = l10n_util::GetString(IDS_ALWAYS_ON_TOP);
+
+ // Let's insert a menu to the window.
+ HMENU system_menu = ::GetSystemMenu(GetHWND(), FALSE);
+ int index = ::GetMenuItemCount(system_menu) - 1;
+ if (index < 0) {
+ // Paranoia check.
+ NOTREACHED();
+ index = 0;
+ }
+ // First we add the separator.
+ MENUITEMINFO menu_info;
+ memset(&menu_info, 0, sizeof(MENUITEMINFO));
+ menu_info.cbSize = sizeof(MENUITEMINFO);
+ menu_info.fMask = MIIM_FTYPE;
+ menu_info.fType = MFT_SEPARATOR;
+ ::InsertMenuItem(system_menu, index, TRUE, &menu_info);
+
+ // Then the actual menu.
+ menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE;
+ menu_info.fType = MFT_STRING;
+ menu_info.fState = MFS_ENABLED;
+ if (is_always_on_top_)
+ menu_info.fState |= MFS_CHECKED;
+ menu_info.wID = IDC_ALWAYS_ON_TOP;
+ menu_info.dwTypeData = const_cast<wchar_t*>(always_on_top_menu_text_.c_str());
+ ::InsertMenuItem(system_menu, index, TRUE, &menu_info);
+}
+
+void Window::RestoreEnabledIfNecessary() {
+ if (is_modal_ && !restored_enabled_) {
+ restored_enabled_ = true;
+ // If we were run modally, we need to undo the disabled-ness we inflicted on
+ // the owner's parent hierarchy.
+ HWND start = owning_hwnd_;
+ while (start != NULL) {
+ ::EnableWindow(start, TRUE);
+ start = ::GetParent(start);
+ }
+ }
+}
+
+void Window::AlwaysOnTopChanged() {
+ ::SetWindowPos(GetHWND(),
+ is_always_on_top_ ? HWND_TOPMOST : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+}
+
+DWORD Window::CalculateWindowStyle() {
+ if (window_delegate_) {
+ DWORD window_styles = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SYSMENU;
+ bool can_resize = window_delegate_->CanResize();
+ bool can_maximize = window_delegate_->CanMaximize();
+ if ((can_resize && can_maximize) || can_maximize) {
+ window_styles |= WS_OVERLAPPEDWINDOW;
+ } else if (can_resize) {
+ window_styles |= WS_OVERLAPPED | WS_THICKFRAME;
+ }
+ if (window_delegate_->AsDialogDelegate()) {
+ window_styles |= DS_MODALFRAME;
+ // NOTE: Turning this off means we lose the close button, which is bad.
+ // Turning it on though means the user can maximize or size the window
+ // from the system menu, which is worse. We may need to provide our own
+ // menu to get the close button to appear properly.
+ // window_styles &= ~WS_SYSMENU;
+ }
+ return window_styles;
+ }
+ return window_style();
+}
+
+DWORD Window::CalculateWindowExStyle() {
+ if (window_delegate_) {
+ DWORD window_ex_styles = 0;
+ if (window_delegate_->AsDialogDelegate()) {
+ window_ex_styles |= WS_EX_DLGMODALFRAME;
+ } else if (!(window_style() & WS_CHILD)) {
+ window_ex_styles |= WS_EX_APPWINDOW;
+ }
+ if (window_delegate_->IsAlwaysOnTop())
+ window_ex_styles |= WS_EX_TOPMOST;
+ return window_ex_styles;
+ }
+ return window_ex_style();
+}
+
+void Window::SaveWindowPosition() {
+ if (window_delegate_) {
+ WINDOWPLACEMENT win_placement = { 0 };
+ win_placement.length = sizeof(WINDOWPLACEMENT);
+
+ BOOL r = GetWindowPlacement(GetHWND(), &win_placement);
+ DCHECK(r);
+
+ bool maximized = (win_placement.showCmd == SW_SHOWMAXIMIZED);
+ CRect window_bounds(win_placement.rcNormalPosition);
+ window_delegate_->SaveWindowPosition(window_bounds,
+ maximized,
+ is_always_on_top_);
+ }
+}
+
+void Window::InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ nwse_cursor_ = LoadCursor(NULL, IDC_SIZENWSE);
+ initialized = true;
+ }
+}
+
+} // namespace ChromeViews