diff options
Diffstat (limited to 'ui/gfx')
-rw-r--r-- | ui/gfx/canvas_paint_win.h | 2 | ||||
-rw-r--r-- | ui/gfx/display.cc | 2 | ||||
-rw-r--r-- | ui/gfx/font_smoothing_win.cc | 6 | ||||
-rw-r--r-- | ui/gfx/platform_font_win.cc | 6 | ||||
-rw-r--r-- | ui/gfx/render_text.cc | 6 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.cc | 10 | ||||
-rw-r--r-- | ui/gfx/render_text_win.cc | 12 | ||||
-rw-r--r-- | ui/gfx/screen_win.cc | 2 | ||||
-rw-r--r-- | ui/gfx/switches.cc | 5 | ||||
-rw-r--r-- | ui/gfx/switches.h | 3 | ||||
-rw-r--r-- | ui/gfx/sys_color_change_listener.cc | 8 | ||||
-rw-r--r-- | ui/gfx/utf16_indexing.cc | 55 | ||||
-rw-r--r-- | ui/gfx/utf16_indexing.h | 49 | ||||
-rw-r--r-- | ui/gfx/utf16_indexing_unittest.cc | 32 | ||||
-rw-r--r-- | ui/gfx/win/dpi.cc (renamed from ui/gfx/dpi_win.cc) | 6 | ||||
-rw-r--r-- | ui/gfx/win/dpi.h (renamed from ui/gfx/dpi_win.h) | 0 | ||||
-rw-r--r-- | ui/gfx/win/hwnd_util.cc | 214 | ||||
-rw-r--r-- | ui/gfx/win/hwnd_util.h | 54 | ||||
-rw-r--r-- | ui/gfx/win/scoped_set_map_mode.h | 40 | ||||
-rw-r--r-- | ui/gfx/win/singleton_hwnd.cc | 55 | ||||
-rw-r--r-- | ui/gfx/win/singleton_hwnd.h | 61 | ||||
-rw-r--r-- | ui/gfx/win/window_impl.cc | 272 | ||||
-rw-r--r-- | ui/gfx/win/window_impl.h | 123 |
23 files changed, 989 insertions, 34 deletions
diff --git a/ui/gfx/canvas_paint_win.h b/ui/gfx/canvas_paint_win.h index ed31a6e..c5d3aee 100644 --- a/ui/gfx/canvas_paint_win.h +++ b/ui/gfx/canvas_paint_win.h @@ -7,8 +7,8 @@ #include "skia/ext/platform_canvas.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/dpi_win.h" #include "ui/gfx/size.h" +#include "ui/gfx/win/dpi.h" namespace gfx { diff --git a/ui/gfx/display.cc b/ui/gfx/display.cc index 02d97a9..d3f0745 100644 --- a/ui/gfx/display.cc +++ b/ui/gfx/display.cc @@ -8,11 +8,11 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" -#include "ui/base/ui_base_switches.h" #include "ui/gfx/insets.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/point_f.h" #include "ui/gfx/size_conversions.h" +#include "ui/gfx/switches.h" namespace gfx { namespace { diff --git a/ui/gfx/font_smoothing_win.cc b/ui/gfx/font_smoothing_win.cc index a4be729..b181fb5 100644 --- a/ui/gfx/font_smoothing_win.cc +++ b/ui/gfx/font_smoothing_win.cc @@ -5,13 +5,13 @@ #include "ui/gfx/font_smoothing_win.h" #include "base/memory/singleton.h" -#include "ui/base/win/singleton_hwnd.h" +#include "ui/gfx/win/singleton_hwnd.h" namespace { // Helper class to cache font smoothing settings and listen for notifications // to re-query them from the system. -class CachedFontSmoothingSettings : public ui::SingletonHwnd::Observer { +class CachedFontSmoothingSettings : public gfx::SingletonHwnd::Observer { public: static CachedFontSmoothingSettings* GetInstance(); @@ -66,7 +66,7 @@ void CachedFontSmoothingSettings::GetFontSmoothingSettings( need_to_query_settings_ = false; } if (!observer_added_) { - ui::SingletonHwnd::GetInstance()->AddObserver(this); + gfx::SingletonHwnd::GetInstance()->AddObserver(this); observer_added_ = true; } *smoothing_enabled = smoothing_enabled_; diff --git a/ui/gfx/platform_font_win.cc b/ui/gfx/platform_font_win.cc index 4a792f6..2d4c006 100644 --- a/ui/gfx/platform_font_win.cc +++ b/ui/gfx/platform_font_win.cc @@ -17,9 +17,9 @@ #include "base/win/scoped_hdc.h" #include "base/win/scoped_select_object.h" #include "base/win/win_util.h" -#include "ui/base/win/scoped_set_map_mode.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" +#include "ui/gfx/win/scoped_set_map_mode.h" namespace { @@ -229,7 +229,7 @@ PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRef(HFONT font) { { base::win::ScopedGetDC screen_dc(NULL); base::win::ScopedSelectObject scoped_font(screen_dc, font); - ui::ScopedSetMapMode mode(screen_dc, MM_TEXT); + gfx::ScopedSetMapMode mode(screen_dc, MM_TEXT); GetTextMetrics(screen_dc, &font_metrics); } @@ -284,7 +284,7 @@ int PlatformFontWin::HFontRef::GetDluBaseX() { base::win::ScopedGetDC screen_dc(NULL); base::win::ScopedSelectObject font(screen_dc, hfont_); - ui::ScopedSetMapMode mode(screen_dc, MM_TEXT); + gfx::ScopedSetMapMode mode(screen_dc, MM_TEXT); // Yes, this is how Microsoft recommends calculating the dialog unit // conversions. See: http://support.microsoft.com/kb/125681 diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 06640e0..c4335b4 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -13,12 +13,12 @@ #include "third_party/icu/source/common/unicode/utf16.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/effects/SkGradientShader.h" -#include "ui/base/text/utf16_indexing.h" #include "ui/gfx/canvas.h" #include "ui/gfx/insets.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/text_constants.h" #include "ui/gfx/text_elider.h" +#include "ui/gfx/utf16_indexing.h" namespace gfx { @@ -952,7 +952,7 @@ void RenderText::UpdateLayoutText() { if (obscured_) { size_t obscured_text_length = - static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, text_.length())); + static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length())); layout_text_.assign(obscured_text_length, kPasswordReplacementChar); if (obscured_reveal_index_ >= 0 && @@ -966,7 +966,7 @@ void RenderText::UpdateLayoutText() { // Gets the index in |layout_text_| to be replaced. const size_t cp_start = - static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, start)); + static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, start)); if (layout_text_.length() > cp_start) layout_text_.replace(cp_start, 1, text_.substr(start, end - start)); } diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc index c6cf4f2..9ad2a3d 100644 --- a/ui/gfx/render_text_linux.cc +++ b/ui/gfx/render_text_linux.cc @@ -12,11 +12,11 @@ #include "base/i18n/break_iterator.h" #include "base/logging.h" #include "third_party/skia/include/core/SkTypeface.h" -#include "ui/base/text/utf16_indexing.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" #include "ui/gfx/font_render_params_linux.h" #include "ui/gfx/pango_util.h" +#include "ui/gfx/utf16_indexing.h" namespace gfx { @@ -252,7 +252,7 @@ std::vector<Rect> RenderTextLinux::GetSubstringBounds(const gfx::Range& range) { size_t RenderTextLinux::TextIndexToLayoutIndex(size_t index) const { DCHECK(layout_); - ptrdiff_t offset = ui::UTF16IndexToOffset(text(), 0, index); + ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index); // Clamp layout indices to the length of the text actually used for layout. offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1)); const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset); @@ -263,7 +263,7 @@ size_t RenderTextLinux::LayoutIndexToTextIndex(size_t index) const { DCHECK(layout_); const char* layout_pointer = layout_text_ + index; const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer); - return ui::UTF16OffsetToIndex(text(), 0, offset); + return gfx::UTF16OffsetToIndex(text(), 0, offset); } bool RenderTextLinux::IsCursorablePosition(size_t position) { @@ -271,11 +271,11 @@ bool RenderTextLinux::IsCursorablePosition(size_t position) { return true; if (position >= text().length()) return position == text().length(); - if (!ui::IsValidCodePointIndex(text(), position)) + if (!gfx::IsValidCodePointIndex(text(), position)) return false; EnsureLayout(); - ptrdiff_t offset = ui::UTF16IndexToOffset(text(), 0, position); + ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position); // Check that the index corresponds with a valid text code point, that it is // marked as a legitimate cursor position by Pango, and that it is not // truncated from layout text (its glyph is shown on screen). diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 2415060..2eff381 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -14,11 +14,11 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "third_party/icu/source/common/unicode/uchar.h" -#include "ui/base/text/utf16_indexing.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_fallback_win.h" #include "ui/gfx/font_smoothing_win.h" #include "ui/gfx/platform_font_win.h" +#include "ui/gfx/utf16_indexing.h" namespace gfx { @@ -413,7 +413,7 @@ std::vector<Rect> RenderTextWin::GetSubstringBounds(const gfx::Range& range) { size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { DCHECK_LE(index, text().length()); - ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index; + ptrdiff_t i = obscured() ? gfx::UTF16IndexToOffset(text(), 0, index) : index; CHECK_GE(i, 0); // Clamp layout indices to the length of the text actually used for layout. return std::min<size_t>(GetLayoutText().length(), i); @@ -424,7 +424,7 @@ size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const { return index; DCHECK_LE(index, GetLayoutText().length()); - const size_t text_index = ui::UTF16OffsetToIndex(text(), 0, index); + const size_t text_index = gfx::UTF16OffsetToIndex(text(), 0, index); DCHECK_LE(text_index, text().length()); return text_index; } @@ -439,7 +439,7 @@ bool RenderTextWin::IsCursorablePosition(size_t position) { // and that its glyph has distinct bounds (not mid-multi-character-grapheme). // An example of a multi-character-grapheme that is not a surrogate-pair is: // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts. - return ui::IsValidCodePointIndex(text(), position) && + return gfx::IsValidCodePointIndex(text(), position) && position < LayoutIndexToTextIndex(GetLayoutText().length()) && GetGlyphBounds(position) != GetGlyphBounds(position - 1); } @@ -599,7 +599,7 @@ void RenderTextWin::ItemizeLogicalText() { // Clamp run lengths to avoid exceeding the maximum supported glyph count. if ((run_break - run->range.start()) > max_run_length) { run_break = run->range.start() + max_run_length; - if (!ui::IsValidCodePointIndex(layout_text, run_break)) + if (!gfx::IsValidCodePointIndex(layout_text, run_break)) --run_break; } @@ -619,7 +619,7 @@ void RenderTextWin::ItemizeLogicalText() { } } - DCHECK(ui::IsValidCodePointIndex(layout_text, run_break)); + DCHECK(gfx::IsValidCodePointIndex(layout_text, run_break)); style.UpdatePosition(LayoutIndexToTextIndex(run_break)); if (script_item_break == run_break) diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc index 7ae5306..7903cc5 100644 --- a/ui/gfx/screen_win.cc +++ b/ui/gfx/screen_win.cc @@ -11,7 +11,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/win_util.h" #include "ui/gfx/display.h" -#include "ui/gfx/dpi_win.h" +#include "ui/gfx/win/dpi.h" namespace { diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc index a278f46..2f2eb9a 100644 --- a/ui/gfx/switches.cc +++ b/ui/gfx/switches.cc @@ -4,7 +4,6 @@ #include "ui/gfx/switches.h" -namespace gfx { namespace switches { // Let text glyphs have X-positions that aren't snapped to the pixel grid in @@ -17,8 +16,10 @@ const char kEnableBrowserTextSubpixelPositioning[] = const char kEnableWebkitTextSubpixelPositioning[] = "enable-webkit-text-subpixel-positioning"; +// Overrides the device scale factor for the browser UI and the contents. +const char kForceDeviceScaleFactor[] = "force-device-scale-factor"; + // Enables/Disables High DPI support (windows) const char kHighDPISupport[] = "high-dpi-support"; } // namespace switches -} // namespace gfx diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h index f8069d0..e3cd9e7 100644 --- a/ui/gfx/switches.h +++ b/ui/gfx/switches.h @@ -7,14 +7,13 @@ #include "ui/gfx/gfx_export.h" -namespace gfx { namespace switches { UI_EXPORT extern const char kEnableBrowserTextSubpixelPositioning[]; UI_EXPORT extern const char kEnableWebkitTextSubpixelPositioning[]; +UI_EXPORT extern const char kForceDeviceScaleFactor[]; UI_EXPORT extern const char kHighDPISupport[]; } // namespace switches -} // namespace gfx #endif // UI_GFX_SWITCHES_H_ diff --git a/ui/gfx/sys_color_change_listener.cc b/ui/gfx/sys_color_change_listener.cc index 7a9fc84..d5646b3 100644 --- a/ui/gfx/sys_color_change_listener.cc +++ b/ui/gfx/sys_color_change_listener.cc @@ -13,7 +13,7 @@ #include "base/memory/singleton.h" #include "base/observer_list.h" #if defined(OS_WIN) -#include "ui/base/win/singleton_hwnd.h" +#include "ui/gfx/win/singleton_hwnd.h" #endif namespace gfx { @@ -48,7 +48,7 @@ bool IsInvertedColorScheme() { } #if defined(OS_WIN) -class SysColorChangeObserver : public ui::SingletonHwnd::Observer { +class SysColorChangeObserver : public gfx::SingletonHwnd::Observer { public: static SysColorChangeObserver* GetInstance(); @@ -75,11 +75,11 @@ SysColorChangeObserver* SysColorChangeObserver::GetInstance() { } SysColorChangeObserver::SysColorChangeObserver() { - ui::SingletonHwnd::GetInstance()->AddObserver(this); + gfx::SingletonHwnd::GetInstance()->AddObserver(this); } SysColorChangeObserver::~SysColorChangeObserver() { - ui::SingletonHwnd::GetInstance()->RemoveObserver(this); + gfx::SingletonHwnd::GetInstance()->RemoveObserver(this); } void SysColorChangeObserver::AddListener(SysColorChangeListener* listener) { diff --git a/ui/gfx/utf16_indexing.cc b/ui/gfx/utf16_indexing.cc new file mode 100644 index 0000000..6af10c1 --- /dev/null +++ b/ui/gfx/utf16_indexing.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/utf16_indexing.h" + +#include "base/logging.h" +#include "base/third_party/icu/icu_utf.h" + +namespace gfx { + +bool IsValidCodePointIndex(const string16& s, size_t index) { + return index == 0 || index == s.length() || + !(CBU16_IS_TRAIL(s[index]) && CBU16_IS_LEAD(s[index - 1])); +} + +ptrdiff_t UTF16IndexToOffset(const string16& s, size_t base, size_t pos) { + // The indices point between UTF-16 words (range 0 to s.length() inclusive). + // In order to consistently handle indices that point to the middle of a + // surrogate pair, we count the first word in that surrogate pair and not + // the second. The test "s[i] is not the second half of a surrogate pair" is + // "IsValidCodePointIndex(s, i)". + DCHECK_LE(base, s.length()); + DCHECK_LE(pos, s.length()); + ptrdiff_t delta = 0; + while (base < pos) + delta += IsValidCodePointIndex(s, base++) ? 1 : 0; + while (pos < base) + delta -= IsValidCodePointIndex(s, pos++) ? 1 : 0; + return delta; +} + +size_t UTF16OffsetToIndex(const string16& s, size_t base, ptrdiff_t offset) { + DCHECK_LE(base, s.length()); + // As in UTF16IndexToOffset, we count the first half of a surrogate pair, not + // the second. When stepping from pos to pos+1 we check s[pos:pos+1] == s[pos] + // (Python syntax), hence pos++. When stepping from pos to pos-1 we check + // s[pos-1], hence --pos. + size_t pos = base; + while (offset > 0 && pos < s.length()) + offset -= IsValidCodePointIndex(s, pos++) ? 1 : 0; + while (offset < 0 && pos > 0) + offset += IsValidCodePointIndex(s, --pos) ? 1 : 0; + // If offset != 0 then we ran off the edge of the string, which is a contract + // violation but is handled anyway (by clamping) in release for safety. + DCHECK_EQ(offset, 0); + // Since the second half of a surrogate pair has "length" zero, there is an + // ambiguity in the returned position. Resolve it by always returning a valid + // index. + if (!IsValidCodePointIndex(s, pos)) + ++pos; + return pos; +} + +} // namespace gfx diff --git a/ui/gfx/utf16_indexing.h b/ui/gfx/utf16_indexing.h new file mode 100644 index 0000000..7f56384 --- /dev/null +++ b/ui/gfx/utf16_indexing.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_UTF16_INDEXING_H_ +#define UI_GFX_UTF16_INDEXING_H_ + +#include "base/strings/string16.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +// Returns false if s[index-1] is a high surrogate and s[index] is a low +// surrogate, true otherwise. +UI_EXPORT bool IsValidCodePointIndex(const string16& s, size_t index); + +// |UTF16IndexToOffset| returns the number of code points between |base| and +// |pos| in the given string. |UTF16OffsetToIndex| returns the index that is +// |offset| code points away from the given |base| index. These functions are +// named after glib's |g_utf8_pointer_to_offset| and |g_utf8_offset_to_pointer|, +// which perform the same function for UTF-8. As in glib, it is an error to +// pass an |offset| that walks off the edge of the string. +// +// These functions attempt to deal with invalid use of UTF-16 surrogates in a +// way that makes as much sense as possible: unpaired surrogates are treated as +// single characters, and if an argument index points to the middle of a valid +// surrogate pair, it is treated as though it pointed to the end of that pair. +// The index returned by |UTF16OffsetToIndex| never points to the middle of a +// surrogate pair. +// +// The following identities hold: +// If |s| contains no surrogate pairs, then +// UTF16IndexToOffset(s, base, pos) == pos - base +// UTF16OffsetToIndex(s, base, offset) == base + offset +// If |pos| does not point to the middle of a surrogate pair, then +// UTF16OffsetToIndex(s, base, UTF16IndexToOffset(s, base, pos)) == pos +// Always, +// UTF16IndexToOffset(s, base, UTF16OffsetToIndex(s, base, ofs)) == ofs +// UTF16IndexToOffset(s, i, j) == -UTF16IndexToOffset(s, j, i) +UI_EXPORT ptrdiff_t UTF16IndexToOffset(const string16& s, + size_t base, + size_t pos); +UI_EXPORT size_t UTF16OffsetToIndex(const string16& s, + size_t base, + ptrdiff_t offset); + +} // namespace gfx + +#endif // UI_GFX_UTF16_INDEXING_H_ diff --git a/ui/gfx/utf16_indexing_unittest.cc b/ui/gfx/utf16_indexing_unittest.cc new file mode 100644 index 0000000..da2f8f5b --- /dev/null +++ b/ui/gfx/utf16_indexing_unittest.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/utf16_indexing.h" + +namespace gfx { + +TEST(UTF16IndexingTest, IndexOffsetConversions) { + // Valid surrogate pair surrounded by unpaired surrogates + const char16 foo[] = {0xDC00, 0xD800, 0xD800, 0xDFFF, 0xDFFF, 0xDBFF, 0}; + const string16 s(foo); + const size_t the_invalid_index = 3; + for (size_t i = 0; i <= s.length(); ++i) + EXPECT_EQ(i != the_invalid_index, IsValidCodePointIndex(s, i)); + for (size_t i = 0; i <= s.length(); ++i) { + for (size_t j = i; j <= s.length(); ++j) { + ptrdiff_t offset = static_cast<ptrdiff_t>(j - i); + if (i <= the_invalid_index && j > the_invalid_index) + --offset; + EXPECT_EQ(offset, UTF16IndexToOffset(s, i, j)); + EXPECT_EQ(-offset, UTF16IndexToOffset(s, j, i)); + size_t adjusted_j = (j == the_invalid_index) ? j + 1 : j; + EXPECT_EQ(adjusted_j, UTF16OffsetToIndex(s, i, offset)); + size_t adjusted_i = (i == the_invalid_index) ? i + 1 : i; + EXPECT_EQ(adjusted_i, UTF16OffsetToIndex(s, j, -offset)); + } + } +} + +} // namespace gfx diff --git a/ui/gfx/dpi_win.cc b/ui/gfx/win/dpi.cc index 51972d2..98d23bd 100644 --- a/ui/gfx/dpi_win.cc +++ b/ui/gfx/win/dpi.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/gfx/dpi_win.h" +#include "ui/gfx/win/dpi.h" #include <windows.h> #include "base/command_line.h" @@ -25,9 +25,9 @@ int kDefaultDPIY = 96; bool IsHighDPIEnabled() { // Default is disabled. if (CommandLine::ForCurrentProcess()->HasSwitch( - gfx::switches::kHighDPISupport)) { + switches::kHighDPISupport)) { return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - gfx::switches::kHighDPISupport).compare("1") == 0; + switches::kHighDPISupport).compare("1") == 0; } return false; } diff --git a/ui/gfx/dpi_win.h b/ui/gfx/win/dpi.h index a056f53..a056f53 100644 --- a/ui/gfx/dpi_win.h +++ b/ui/gfx/win/dpi.h diff --git a/ui/gfx/win/hwnd_util.cc b/ui/gfx/win/hwnd_util.cc new file mode 100644 index 0000000..91f0ddd --- /dev/null +++ b/ui/gfx/win/hwnd_util.cc @@ -0,0 +1,214 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/win/hwnd_util.h" + +#include "base/i18n/rtl.h" +#include "base/strings/string_util.h" +#include "base/win/metro.h" +#include "base/win/win_util.h" +#include "ui/gfx/point.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" + +namespace gfx { + +namespace { + +// Adjust the window to fit. +void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) { + if (fit_to_monitor) { + // Get the monitor. + HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST); + if (hmon) { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + base::win::GetMonitorInfoWrapper(hmon, &mi); + Rect window_rect(bounds); + Rect monitor_rect(mi.rcWork); + Rect new_window_rect = window_rect; + new_window_rect.AdjustToFit(monitor_rect); + if (new_window_rect != window_rect) { + // Window doesn't fit on monitor, move and possibly resize. + SetWindowPos(hwnd, 0, new_window_rect.x(), new_window_rect.y(), + new_window_rect.width(), new_window_rect.height(), + SWP_NOACTIVATE | SWP_NOZORDER); + return; + } + // Else fall through. + } else { + NOTREACHED() << "Unable to find default monitor"; + // Fall through. + } + } // Else fall through. + + // The window is not being fit to monitor, or the window fits on the monitor + // as is, or we have no monitor info; reset the bounds. + ::SetWindowPos(hwnd, 0, bounds.left, bounds.top, + bounds.right - bounds.left, bounds.bottom - bounds.top, + SWP_NOACTIVATE | SWP_NOZORDER); +} + +} // namespace + +string16 GetClassName(HWND window) { + // GetClassNameW will return a truncated result (properly null terminated) if + // the given buffer is not large enough. So, it is not possible to determine + // that we got the entire class name if the result is exactly equal to the + // size of the buffer minus one. + DWORD buffer_size = MAX_PATH; + while (true) { + std::wstring output; + DWORD size_ret = + GetClassNameW(window, WriteInto(&output, buffer_size), buffer_size); + if (size_ret == 0) + break; + if (size_ret < (buffer_size - 1)) { + output.resize(size_ret); + return output; + } + buffer_size *= 2; + } + return std::wstring(); // error +} + +#pragma warning(push) +#pragma warning(disable:4312 4244) + +WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) { + // The reason we don't return the SetwindowLongPtr() value is that it returns + // the orignal window procedure and not the current one. I don't know if it is + // a bug or an intended feature. + WNDPROC oldwindow_proc = + reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC)); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc)); + return oldwindow_proc; +} + +void* SetWindowUserData(HWND hwnd, void* user_data) { + return + reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA, + reinterpret_cast<LONG_PTR>(user_data))); +} + +void* GetWindowUserData(HWND hwnd) { + DWORD process_id = 0; + DWORD thread_id = GetWindowThreadProcessId(hwnd, &process_id); + // A window outside the current process needs to be ignored. + if (process_id != ::GetCurrentProcessId()) + return NULL; + return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); +} + +#pragma warning(pop) + +bool DoesWindowBelongToActiveWindow(HWND window) { + DCHECK(window); + HWND top_window = ::GetAncestor(window, GA_ROOT); + if (!top_window) + return false; + + HWND active_top_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT); + return (top_window == active_top_window); +} + +void CenterAndSizeWindow(HWND parent, + HWND window, + const Size& pref) { + DCHECK(window && pref.width() > 0 && pref.height() > 0); + + // Calculate the ideal bounds. + RECT window_bounds; + RECT center_bounds = {0}; + if (parent) { + // If there is a parent, center over the parents bounds. + ::GetWindowRect(parent, ¢er_bounds); + } + + if (::IsRectEmpty(¢er_bounds)) { + // No parent or no parent rect. Center over the monitor the window is on. + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST); + if (monitor) { + MONITORINFO mi = {0}; + mi.cbSize = sizeof(mi); + base::win::GetMonitorInfoWrapper(monitor, &mi); + center_bounds = mi.rcWork; + } else { + NOTREACHED() << "Unable to get default monitor"; + } + } + + window_bounds.left = center_bounds.left; + if (pref.width() < (center_bounds.right - center_bounds.left)) { + window_bounds.left += + (center_bounds.right - center_bounds.left - pref.width()) / 2; + } + window_bounds.right = window_bounds.left + pref.width(); + + window_bounds.top = center_bounds.top; + if (pref.height() < (center_bounds.bottom - center_bounds.top)) { + window_bounds.top += + (center_bounds.bottom - center_bounds.top - pref.height()) / 2; + } + window_bounds.bottom = window_bounds.top + pref.height(); + + // If we're centering a child window, we are positioning in client + // coordinates, and as such we need to offset the target rectangle by the + // position of the parent window. + if (::GetWindowLong(window, GWL_STYLE) & WS_CHILD) { + DCHECK(parent && ::GetParent(window) == parent); + POINT topleft = { window_bounds.left, window_bounds.top }; + ::MapWindowPoints(HWND_DESKTOP, parent, &topleft, 1); + window_bounds.left = topleft.x; + window_bounds.top = topleft.y; + window_bounds.right = window_bounds.left + pref.width(); + window_bounds.bottom = window_bounds.top + pref.height(); + } + + AdjustWindowToFit(window, window_bounds, !parent); +} + +void CheckWindowCreated(HWND hwnd) { + if (!hwnd) + LOG_GETLASTERROR(FATAL); +} + +void ShowSystemMenu(HWND window) { + RECT rect; + GetWindowRect(window, &rect); + Point point = Point(rect.left, rect.top); + static const int kSystemMenuOffset = 10; + point.Offset(kSystemMenuOffset, kSystemMenuOffset); + ShowSystemMenuAtPoint(window, point); +} + +void ShowSystemMenuAtPoint(HWND window, const Point& point) { + // In the Metro process, we never want to show the system menu. + if (base::win::IsMetroProcess()) + return; + UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD; + if (base::i18n::IsRTL()) + flags |= TPM_RIGHTALIGN; + HMENU menu = GetSystemMenu(window, FALSE); + const int command = + TrackPopupMenu(menu, flags, point.x(), point.y(), 0, window, NULL); + if (command) + SendMessage(window, WM_SYSCOMMAND, command, 0); +} + +extern "C" { + typedef HWND (*RootWindow)(); +} + +HWND GetWindowToParentTo(bool get_real_hwnd) { + HMODULE metro = base::win::GetMetroModule(); + if (!metro) + return get_real_hwnd ? ::GetDesktopWindow() : HWND_DESKTOP; + // In windows 8 metro-mode the root window is not the desktop. + RootWindow root_window = + reinterpret_cast<RootWindow>(::GetProcAddress(metro, "GetRootWindow")); + return root_window(); +} + +} // namespace gfx diff --git a/ui/gfx/win/hwnd_util.h b/ui/gfx/win/hwnd_util.h new file mode 100644 index 0000000..70e5f8f --- /dev/null +++ b/ui/gfx/win/hwnd_util.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_WIN_HWND_UTIL_H_ +#define UI_GFX_WIN_HWND_UTIL_H_ + +#include <windows.h> + +#include "base/strings/string16.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { +class Point; +class Size; + +// A version of the GetClassNameW API that returns the class name in an +// string16. An empty result indicates a failure to get the class name. +UI_EXPORT string16 GetClassName(HWND hwnd); + +// Useful for subclassing a HWND. Returns the previous window procedure. +UI_EXPORT WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc); + +// Pointer-friendly wrappers around Get/SetWindowLong(..., GWLP_USERDATA, ...) +// Returns the previously set value. +UI_EXPORT void* SetWindowUserData(HWND hwnd, void* user_data); +UI_EXPORT void* GetWindowUserData(HWND hwnd); + +// Returns true if the specified window is the current active top window or one +// of its children. +UI_EXPORT bool DoesWindowBelongToActiveWindow(HWND window); + +// Sizes the window to have a window size of |pref|, then centers the window +// over |parent|, ensuring the window fits on screen. +UI_EXPORT void CenterAndSizeWindow(HWND parent, + HWND window, + const gfx::Size& pref); + +// If |hwnd| is NULL logs various thing and CHECKs. Invoke right after calling +// CreateWindow. +UI_EXPORT void CheckWindowCreated(HWND hwnd); + +// Shows |window|'s system menu (at a specified |point| in screen coordinates). +UI_EXPORT void ShowSystemMenu(HWND window); +UI_EXPORT void ShowSystemMenuAtPoint(HWND window, const gfx::Point& point); + +// Returns the window you can use to parent a top level window. +// Note that in some cases we create child windows not parented to its final +// container so in those cases you should pass true in |get_real_hwnd|. +UI_EXPORT HWND GetWindowToParentTo(bool get_real_hwnd); + +} // namespace gfx + +#endif // UI_GFX_WIN_HWND_UTIL_H_ diff --git a/ui/gfx/win/scoped_set_map_mode.h b/ui/gfx/win/scoped_set_map_mode.h new file mode 100644 index 0000000..910837d --- /dev/null +++ b/ui/gfx/win/scoped_set_map_mode.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_WIN_SCOPED_SET_MAP_MODE_H_ +#define UI_GFX_WIN_SCOPED_SET_MAP_MODE_H_ + +#include <windows.h> + +#include "base/basictypes.h" +#include "base/logging.h" + +namespace gfx { + +// Helper class for setting and restore the map mode on a DC. +class ScopedSetMapMode { + public: + ScopedSetMapMode(HDC hdc, int map_mode) + : hdc_(hdc), + old_map_mode_(SetMapMode(hdc, map_mode)) { + DCHECK(hdc_); + DCHECK_NE(map_mode, 0); + DCHECK_NE(old_map_mode_, 0); + } + + ~ScopedSetMapMode() { + const int mode = SetMapMode(hdc_, old_map_mode_); + DCHECK_NE(mode, 0); + } + + private: + HDC hdc_; + int old_map_mode_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSetMapMode); +}; + +} // namespace gfx + +#endif // UI_GFX_WIN_SCOPED_SET_MAP_MODE_H_ diff --git a/ui/gfx/win/singleton_hwnd.cc b/ui/gfx/win/singleton_hwnd.cc new file mode 100644 index 0000000..37993e8 --- /dev/null +++ b/ui/gfx/win/singleton_hwnd.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/win/singleton_hwnd.h" + +#include "base/memory/singleton.h" +#include "base/message_loop/message_loop.h" + +namespace gfx { + +// static +SingletonHwnd* SingletonHwnd::GetInstance() { + return Singleton<SingletonHwnd>::get(); +} + +void SingletonHwnd::AddObserver(Observer* observer) { + if (!hwnd()) { + if (!base::MessageLoop::current() || + base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { + // Creating this window in (e.g.) a renderer inhibits shutdown on + // Windows. See http://crbug.com/230122 and http://crbug.com/236039. + DLOG(ERROR) << "Cannot create windows on non-UI thread!"; + return; + } + WindowImpl::Init(NULL, Rect()); + } + observer_list_.AddObserver(observer); +} + +void SingletonHwnd::RemoveObserver(Observer* observer) { + if (!hwnd()) + return; + observer_list_.RemoveObserver(observer); +} + +BOOL SingletonHwnd::ProcessWindowMessage(HWND window, + UINT message, + WPARAM wparam, + LPARAM lparam, + LRESULT& result, + DWORD msg_map_id) { + FOR_EACH_OBSERVER(Observer, + observer_list_, + OnWndProc(window, message, wparam, lparam)); + return false; +} + +SingletonHwnd::SingletonHwnd() { +} + +SingletonHwnd::~SingletonHwnd() { +} + +} // namespace gfx diff --git a/ui/gfx/win/singleton_hwnd.h b/ui/gfx/win/singleton_hwnd.h new file mode 100644 index 0000000..96af6e7 --- /dev/null +++ b/ui/gfx/win/singleton_hwnd.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_WIN_SINGLETON_HWND_H_ +#define UI_GFX_WIN_SINGLETON_HWND_H_ + +#include <windows.h> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback_forward.h" +#include "base/observer_list.h" +#include "ui/gfx/win/window_impl.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace gfx { + +// Singleton message-only HWND that allows interested clients to receive WM_* +// notifications. +class SingletonHwnd : public WindowImpl { + public: + static SingletonHwnd* GetInstance(); + + // Observer interface for receiving Windows WM_* notifications. + class Observer { + public: + virtual void OnWndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) = 0; + }; + + // Add/remove observer to receive WM_* notifications. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Windows callback for WM_* notifications. + virtual BOOL ProcessWindowMessage(HWND window, + UINT message, + WPARAM wparam, + LPARAM lparam, + LRESULT& result, + DWORD msg_map_id) OVERRIDE; + + private: + friend struct DefaultSingletonTraits<SingletonHwnd>; + + SingletonHwnd(); + ~SingletonHwnd(); + + // List of registered observers. + ObserverList<Observer> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(SingletonHwnd); +}; + +} // namespace gfx + +#endif // UI_GFX_WIN_SINGLETON_HWND_H_ diff --git a/ui/gfx/win/window_impl.cc b/ui/gfx/win/window_impl.cc new file mode 100644 index 0000000..e2e6af0 --- /dev/null +++ b/ui/gfx/win/window_impl.cc @@ -0,0 +1,272 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/win/window_impl.h" + +#include <list> + +#include "base/debug/alias.h" +#include "base/memory/singleton.h" +#include "base/strings/string_number_conversions.h" +#include "base/synchronization/lock.h" +#include "base/win/wrapped_window_proc.h" +#include "ui/gfx/win/hwnd_util.h" + +namespace gfx { + +static const DWORD kWindowDefaultChildStyle = + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; +static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; +static const DWORD kWindowDefaultExStyle = 0; + +/////////////////////////////////////////////////////////////////////////////// +// WindowImpl class tracking. + +// Several external scripts rely explicitly on this base class name for +// acquiring the window handle and will break if this is modified! +// static +const wchar_t* const WindowImpl::kBaseClassName = L"Chrome_WidgetWin_"; + +// WindowImpl class information used for registering unique windows. +struct ClassInfo { + UINT style; + HICON icon; + + ClassInfo(int style, HICON icon) + : style(style), + icon(icon) {} + + // Compares two ClassInfos. Returns true if all members match. + bool Equals(const ClassInfo& other) const { + return (other.style == style && other.icon == icon); + } +}; + +// WARNING: this class may be used on multiple threads. +class ClassRegistrar { + public: + ~ClassRegistrar(); + + static ClassRegistrar* GetInstance(); + + // Returns the atom identifying the class matching |class_info|, + // creating and registering a new class if the class is not yet known. + ATOM RetrieveClassAtom(const ClassInfo& class_info); + + private: + // Represents a registered window class. + struct RegisteredClass { + RegisteredClass(const ClassInfo& info, ATOM atom); + + // Info used to create the class. + ClassInfo info; + + // The atom identifying the window class. + ATOM atom; + }; + + ClassRegistrar(); + friend struct DefaultSingletonTraits<ClassRegistrar>; + + typedef std::list<RegisteredClass> RegisteredClasses; + RegisteredClasses registered_classes_; + + // Counter of how many classes have been registered so far. + int registered_count_; + + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(ClassRegistrar); +}; + +ClassRegistrar::~ClassRegistrar() {} + +// static +ClassRegistrar* ClassRegistrar::GetInstance() { + return Singleton<ClassRegistrar, + LeakySingletonTraits<ClassRegistrar> >::get(); +} + +ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) { + base::AutoLock auto_lock(lock_); + for (RegisteredClasses::const_iterator i = registered_classes_.begin(); + i != registered_classes_.end(); ++i) { + if (class_info.Equals(i->info)) + return i->atom; + } + + // No class found, need to register one. + string16 name = string16(WindowImpl::kBaseClassName) + + base::IntToString16(registered_count_++); + + WNDCLASSEX window_class; + base::win::InitializeWindowClass( + name.c_str(), + &base::win::WrappedWindowProc<WindowImpl::WndProc>, + class_info.style, + 0, + 0, + NULL, + NULL, + NULL, + class_info.icon, + class_info.icon, + &window_class); + HMODULE instance = window_class.hInstance; + ATOM atom = RegisterClassEx(&window_class); + CHECK(atom) << GetLastError(); + + registered_classes_.push_back(RegisteredClass(class_info, atom)); + + return atom; +} + +ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info, + ATOM atom) + : info(info), + atom(atom) {} + +ClassRegistrar::ClassRegistrar() : registered_count_(0) {} + + +/////////////////////////////////////////////////////////////////////////////// +// WindowImpl, public + +WindowImpl::WindowImpl() + : window_style_(0), + window_ex_style_(kWindowDefaultExStyle), + class_style_(CS_DBLCLKS), + hwnd_(NULL), + got_create_(false), + got_valid_hwnd_(false), + destroyed_(NULL) { +} + +WindowImpl::~WindowImpl() { + if (destroyed_) + *destroyed_ = true; + ClearUserData(); +} + +void WindowImpl::Init(HWND parent, const Rect& bounds) { + if (window_style_ == 0) + window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle; + + if (parent == HWND_DESKTOP) { + // Only non-child windows can have HWND_DESKTOP (0) as their parent. + CHECK((window_style_ & WS_CHILD) == 0); + parent = GetWindowToParentTo(false); + } else if (parent == ::GetDesktopWindow()) { + // Any type of window can have the "Desktop Window" as their parent. + parent = GetWindowToParentTo(true); + } else if (parent != HWND_MESSAGE) { + CHECK(::IsWindow(parent)); + } + + int x, y, width, height; + if (bounds.IsEmpty()) { + x = y = width = height = CW_USEDEFAULT; + } else { + x = bounds.x(); + y = bounds.y(); + width = bounds.width(); + height = bounds.height(); + } + + ATOM atom = GetWindowClassAtom(); + bool destroyed = false; + destroyed_ = &destroyed; + HWND hwnd = CreateWindowEx(window_ex_style_, + reinterpret_cast<wchar_t*>(atom), NULL, + window_style_, x, y, width, height, + parent, NULL, NULL, this); + + // First nccalcszie (during CreateWindow) for captioned windows is + // deliberately ignored so force a second one here to get the right + // non-client set up. + if (hwnd && (window_style_ & WS_CAPTION)) { + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); + } + + if (!hwnd_ && GetLastError() == 0) { + base::debug::Alias(&destroyed); + base::debug::Alias(&hwnd); + bool got_create = got_create_; + base::debug::Alias(&got_create); + bool got_valid_hwnd = got_valid_hwnd_; + base::debug::Alias(&got_valid_hwnd); + WNDCLASSEX class_info; + memset(&class_info, 0, sizeof(WNDCLASSEX)); + class_info.cbSize = sizeof(WNDCLASSEX); + BOOL got_class = GetClassInfoEx(GetModuleHandle(NULL), + reinterpret_cast<wchar_t*>(atom), + &class_info); + base::debug::Alias(&got_class); + bool procs_match = got_class && class_info.lpfnWndProc == + base::win::WrappedWindowProc<&WindowImpl::WndProc>; + base::debug::Alias(&procs_match); + CHECK(false); + } + if (!destroyed) + destroyed_ = NULL; + + CheckWindowCreated(hwnd_); + + // The window procedure should have set the data for us. + CHECK_EQ(this, GetWindowUserData(hwnd)); +} + +HICON WindowImpl::GetDefaultWindowIcon() const { + return NULL; +} + +LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) { + LRESULT result = 0; + + // Handle the message if it's in our message map; otherwise, let the system + // handle it. + if (!ProcessWindowMessage(hwnd_, message, w_param, l_param, result)) + result = DefWindowProc(hwnd_, message, w_param, l_param); + + return result; +} + +void WindowImpl::ClearUserData() { + if (::IsWindow(hwnd_)) + gfx::SetWindowUserData(hwnd_, NULL); +} + +// static +LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, + UINT message, + WPARAM w_param, + LPARAM l_param) { + if (message == WM_NCCREATE) { + CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param); + WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams); + DCHECK(window); + gfx::SetWindowUserData(hwnd, window); + window->hwnd_ = hwnd; + window->got_create_ = true; + if (hwnd) + window->got_valid_hwnd_ = true; + return TRUE; + } + + WindowImpl* window = reinterpret_cast<WindowImpl*>(GetWindowUserData(hwnd)); + if (!window) + return 0; + + return window->OnWndProc(message, w_param, l_param); +} + +ATOM WindowImpl::GetWindowClassAtom() { + HICON icon = GetDefaultWindowIcon(); + ClassInfo class_info(initial_class_style(), icon); + return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info); +} + +} // namespace gfx diff --git a/ui/gfx/win/window_impl.h b/ui/gfx/win/window_impl.h new file mode 100644 index 0000000..2b0018e --- /dev/null +++ b/ui/gfx/win/window_impl.h @@ -0,0 +1,123 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_WIN_WINDOW_IMPL_H_ +#define UI_GFX_WIN_WINDOW_IMPL_H_ + +#include <atlbase.h> +#include <atlapp.h> +#include <atlmisc.h> +#include <atlcrack.h> + +#include <string> + +#include "base/logging.h" +#include "ui/gfx/gfx_export.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/rect.h" + +namespace gfx { + +// An interface implemented by classes that use message maps. +// ProcessWindowMessage is implemented by the BEGIN_MESSAGE_MAP_EX macro. +class MessageMapInterface { + public: + // Processes one message from the window's message queue. + virtual BOOL ProcessWindowMessage(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT& result, + DWORD msg_map_id = 0) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// WindowImpl +// A convenience class that encapsulates the details of creating and +// destroying a HWND. This class also hosts the windows procedure used by all +// Windows. +// +/////////////////////////////////////////////////////////////////////////////// +class UI_EXPORT WindowImpl : public MessageMapInterface { + public: + WindowImpl(); + virtual ~WindowImpl(); + + // Initializes the Window with a parent and an initial desired size. + void Init(HWND parent, const gfx::Rect& bounds); + + // Returns the default window icon to use for windows of this type. + virtual HICON GetDefaultWindowIcon() const; + + // Returns the HWND associated with this Window. + HWND hwnd() const { return hwnd_; } + + // Sets the window styles. This is ONLY used when the window is created. + // In other words, if you invoke this after invoking Init, nothing happens. + void set_window_style(DWORD style) { window_style_ = style; } + DWORD window_style() const { return window_style_; } + + // Sets the extended window styles. See comment about |set_window_style|. + void set_window_ex_style(DWORD style) { window_ex_style_ = style; } + DWORD window_ex_style() const { return window_ex_style_; } + + // Sets the class style to use. The default is CS_DBLCLKS. + void set_initial_class_style(UINT class_style) { + // We dynamically generate the class name, so don't register it globally! + DCHECK_EQ((class_style & CS_GLOBALCLASS), 0u); + class_style_ = class_style; + } + UINT initial_class_style() const { return class_style_; } + + protected: + // Handles the WndProc callback for this object. + virtual LRESULT OnWndProc(UINT message, WPARAM w_param, LPARAM l_param); + + // Subclasses must call this method from their destructors to ensure that + // this object is properly disassociated from the HWND during destruction, + // otherwise it's possible this object may still exist while a subclass is + // destroyed. + void ClearUserData(); + + private: + friend class ClassRegistrar; + + // The window procedure used by all Windows. + static LRESULT CALLBACK WndProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param); + + // Gets the window class atom to use when creating the corresponding HWND. + // If necessary, this registers the window class. + ATOM GetWindowClassAtom(); + + // All classes registered by WindowImpl start with this name. + static const wchar_t* const kBaseClassName; + + // Window Styles used when creating the window. + DWORD window_style_; + + // Window Extended Styles used when creating the window. + DWORD window_ex_style_; + + // Style of the class to use. + UINT class_style_; + + // Our hwnd. + HWND hwnd_; + + // For debugging. + // TODO(sky): nuke this when get crash data. + bool got_create_; + bool got_valid_hwnd_; + bool* destroyed_; + + DISALLOW_COPY_AND_ASSIGN(WindowImpl); +}; + +} // namespace gfx + +#endif // UI_GFX_WIN_WINDOW_IMPL_H_ |