diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-31 20:39:02 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-31 20:39:02 +0000 |
commit | fd85ad650d68309b965dbc9f3d6823cf2754349c (patch) | |
tree | 28b98629e02b2e05ec74272146f249ca62a164da /app/win | |
parent | ce072a7181ea5d58133e33654133236f5d9f5551 (diff) | |
download | chromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.zip chromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.tar.gz chromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.tar.bz2 |
Move app/win_util to app/win and fix the namespace usage.
Split out the two classes: ScopedComInitializer and ScopedCOMem (which I renamed) to separate files.
I removed the win_util_path file which had one function in it and moved the function to win_util.
Somehow, this was getting picked up by the nacl64 build and the call in sandbox_policy was then not being
defined. I just implemented the function in-plcae since it's just a simple wrapper around a Windows API call.
TEST=it compiles
BUG=none
Review URL: http://codereview.chromium.org/6013009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70343 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app/win')
-rw-r--r-- | app/win/scoped_co_mem.h | 49 | ||||
-rw-r--r-- | app/win/scoped_com_initializer.h | 60 | ||||
-rw-r--r-- | app/win/win_util.cc | 326 | ||||
-rw-r--r-- | app/win/win_util.h | 114 | ||||
-rw-r--r-- | app/win/win_util_unittest.cc | 59 |
5 files changed, 608 insertions, 0 deletions
diff --git a/app/win/scoped_co_mem.h b/app/win/scoped_co_mem.h new file mode 100644 index 0000000..a6017fa --- /dev/null +++ b/app/win/scoped_co_mem.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010 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 APP_WIN_SCOPED_CO_MEM_H_ +#define APP_WIN_SCOPED_CO_MEM_H_ +#pragma once + +#include <objbase.h> + +#include "base/basictypes.h" + +namespace app { +namespace win { + +// Simple scoped memory releaser class for COM allocated memory. +// Example: +// app::win::ScopedCoMem<ITEMIDLIST> file_item; +// SHGetSomeInfo(&file_item, ...); +// ... +// return; <-- memory released +template<typename T> +class ScopedCoMem { + public: + explicit ScopedCoMem() : mem_ptr_(NULL) {} + + ~ScopedCoMem() { + if (mem_ptr_) + CoTaskMemFree(mem_ptr_); + } + + T** operator&() { // NOLINT + return &mem_ptr_; + } + + operator T*() { + return mem_ptr_; + } + + private: + T* mem_ptr_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCoMem); +}; + +} // namespace win +} // namespace app + +#endif // APP_WIN_SCOPED_CO_MEM_H_ diff --git a/app/win/scoped_com_initializer.h b/app/win/scoped_com_initializer.h new file mode 100644 index 0000000..3a2cf55 --- /dev/null +++ b/app/win/scoped_com_initializer.h @@ -0,0 +1,60 @@ +// Copyright (c) 2010 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 APP_WIN_SCOPED_COM_INITIALIZER_H_ +#define APP_WIN_SCOPED_COM_INITIALIZER_H_ +#pragma once + +#include "base/basictypes.h" +#include "build/build_config.h" + +#if defined(OS_WIN) + +#include <objbase.h> + +namespace app { +namespace win { + +// Initializes COM in the constructor (STA), and uninitializes COM in the +// destructor. +class ScopedCOMInitializer { + public: + ScopedCOMInitializer() : hr_(CoInitialize(NULL)) { + } + + ScopedCOMInitializer::~ScopedCOMInitializer() { + if (SUCCEEDED(hr_)) + CoUninitialize(); + } + + private: + HRESULT hr_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer); +}; + +} // namespace win +} // namespace app + +#else + +namespace app { +namespace win { + +// Do-nothing class for other platforms. +class ScopedCOMInitializer { + public: + ScopedCOMInitializer() {} + ~ScopedCOMInitializer() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer); +}; + +} // namespace win +} // namespace app + +#endif + +#endif // APP_WIN_SCOPED_COM_INITIALIZER_H_ diff --git a/app/win/win_util.cc b/app/win/win_util.cc new file mode 100644 index 0000000..f1ac107 --- /dev/null +++ b/app/win/win_util.cc @@ -0,0 +1,326 @@ +// Copyright (c) 2010 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 "app/win/win_util.h" + +#include <commdlg.h> +#include <shellapi.h> + +#include <algorithm> + +#include "app/l10n_util.h" +#include "app/l10n_util_win.h" +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/i18n/rtl.h" +#include "base/logging.h" +#include "base/scoped_handle.h" +#include "base/scoped_handle_win.h" +#include "base/string_util.h" +#include "base/win/scoped_gdi_object.h" +#include "base/win/scoped_hdc.h" +#include "base/win/win_util.h" +#include "gfx/codec/png_codec.h" +#include "gfx/font.h" +#include "gfx/gdi_util.h" + +namespace app { +namespace win { + +const int kAutoHideTaskbarThicknessPx = 2; + +string16 FormatSystemTime(const SYSTEMTIME& time, const string16& format) { + // If the format string is empty, just use the default format. + LPCTSTR format_ptr = NULL; + if (!format.empty()) + format_ptr = format.c_str(); + + int buffer_size = GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr, + NULL, 0); + + string16 output; + GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr, + WriteInto(&output, buffer_size), buffer_size); + + return output; +} + +string16 FormatSystemDate(const SYSTEMTIME& date, const string16& format) { + // If the format string is empty, just use the default format. + LPCTSTR format_ptr = NULL; + if (!format.empty()) + format_ptr = format.c_str(); + + int buffer_size = GetDateFormat(LOCALE_USER_DEFAULT, NULL, &date, format_ptr, + NULL, 0); + + string16 output; + GetDateFormat(LOCALE_USER_DEFAULT, NULL, &date, format_ptr, + WriteInto(&output, buffer_size), buffer_size); + + return output; +} + +bool ConvertToLongPath(const string16& short_path, + string16* long_path) { + wchar_t long_path_buf[MAX_PATH]; + DWORD return_value = GetLongPathName(short_path.c_str(), long_path_buf, + MAX_PATH); + if (return_value != 0 && return_value < MAX_PATH) { + *long_path = long_path_buf; + return true; + } + + return false; +} + +bool IsDoubleClick(const POINT& origin, + const POINT& current, + DWORD elapsed_time) { + // The CXDOUBLECLK and CYDOUBLECLK system metrics describe the width and + // height of a rectangle around the origin position, inside of which clicks + // within the double click time are considered double clicks. + return (elapsed_time <= GetDoubleClickTime()) && + (abs(current.x - origin.x) <= (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) && + (abs(current.y - origin.y) <= (GetSystemMetrics(SM_CYDOUBLECLK) / 2)); +} + +bool IsDrag(const POINT& origin, const POINT& current) { + // The CXDRAG and CYDRAG system metrics describe the width and height of a + // rectangle around the origin position, inside of which motion is not + // considered a drag. + return (abs(current.x - origin.x) > (GetSystemMetrics(SM_CXDRAG) / 2)) || + (abs(current.y - origin.y) > (GetSystemMetrics(SM_CYDRAG) / 2)); +} + +bool EdgeHasTopmostAutoHideTaskbar(UINT edge, HMONITOR monitor) { + APPBARDATA taskbar_data = { 0 }; + taskbar_data.cbSize = sizeof APPBARDATA; + taskbar_data.uEdge = edge; + HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR, + &taskbar_data)); + return ::IsWindow(taskbar) && (monitor != NULL) && + (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) && + (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST); +} + +HANDLE GetSectionFromProcess(HANDLE section, HANDLE process, bool read_only) { + HANDLE valid_section = NULL; + DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ; + if (!read_only) + access |= FILE_MAP_WRITE; + DuplicateHandle(process, section, GetCurrentProcess(), &valid_section, access, + FALSE, 0); + return valid_section; +} + +HANDLE GetSectionForProcess(HANDLE section, HANDLE process, bool read_only) { + HANDLE valid_section = NULL; + DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ; + if (!read_only) + access |= FILE_MAP_WRITE; + DuplicateHandle(GetCurrentProcess(), section, process, &valid_section, access, + FALSE, 0); + return valid_section; +} + +void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect, + gfx::Rect* child_rect, + int padding) { + DCHECK(child_rect); + + // We use padding here because it allows some of the original web page to + // bleed through around the edges. + int twice_padding = padding * 2; + + // FIRST, clamp width and height so we don't open child windows larger than + // the containing parent. + if (child_rect->width() > (parent_rect.width() + twice_padding)) + child_rect->set_width(std::max(0, parent_rect.width() - twice_padding)); + if (child_rect->height() > parent_rect.height() + twice_padding) + child_rect->set_height(std::max(0, parent_rect.height() - twice_padding)); + + // SECOND, clamp x,y position to padding,padding so we don't position child + // windows in hyperspace. + // TODO(mpcomplete): I don't see what the second check in each 'if' does that + // isn't handled by the LAST set of 'ifs'. Maybe we can remove it. + if (child_rect->x() < parent_rect.x() || + child_rect->x() > parent_rect.right()) { + child_rect->set_x(parent_rect.x() + padding); + } + if (child_rect->y() < parent_rect.y() || + child_rect->y() > parent_rect.bottom()) { + child_rect->set_y(parent_rect.y() + padding); + } + + // LAST, nudge the window back up into the client area if its x,y position is + // within the parent bounds but its width/height place it off-screen. + if (child_rect->bottom() > parent_rect.bottom()) + child_rect->set_y(parent_rect.bottom() - child_rect->height() - padding); + if (child_rect->right() > parent_rect.right()) + child_rect->set_x(parent_rect.right() - child_rect->width() - padding); +} + +gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) { + RECT p_rect = rect.ToRECT(); + HMONITOR monitor = MonitorFromRect(&p_rect, MONITOR_DEFAULTTONEAREST); + if (monitor) { + MONITORINFO mi = {0}; + mi.cbSize = sizeof(mi); + GetMonitorInfo(monitor, &mi); + return gfx::Rect(mi.rcWork); + } + NOTREACHED(); + return gfx::Rect(); +} + +bool IsNumPadDigit(int key_code, bool extended_key) { + if (key_code >= VK_NUMPAD0 && key_code <= VK_NUMPAD9) + return true; + + // Check for num pad keys without NumLock. + // Note: there is no easy way to know if a the key that was pressed comes from + // the num pad or the rest of the keyboard. Investigating how + // TranslateMessage() generates the WM_KEYCHAR from an + // ALT + <NumPad sequences> it appears it looks at the extended key flag + // (which is on if the key pressed comes from one of the 3 clusters to + // the left of the numeric keypad). So we use it as well. + return !extended_key && + ((key_code >= VK_PRIOR && key_code <= VK_DOWN) || // All keys but 5 + // and 0. + (key_code == VK_CLEAR) || // Key 5. + (key_code == VK_INSERT)); // Key 0. +} + +void GrabWindowSnapshot(HWND window_handle, + std::vector<unsigned char>* png_representation) { + // Create a memory DC that's compatible with the window. + HDC window_hdc = GetWindowDC(window_handle); + base::win::ScopedHDC mem_hdc(CreateCompatibleDC(window_hdc)); + + // Create a DIB that's the same size as the window. + RECT content_rect = {0, 0, 0, 0}; + ::GetWindowRect(window_handle, &content_rect); + content_rect.right++; // Match what PrintWindow wants. + int width = content_rect.right - content_rect.left; + int height = content_rect.bottom - content_rect.top; + BITMAPINFOHEADER hdr; + gfx::CreateBitmapHeader(width, height, &hdr); + unsigned char *bit_ptr = NULL; + ScopedBitmap bitmap(CreateDIBSection(mem_hdc, + reinterpret_cast<BITMAPINFO*>(&hdr), + DIB_RGB_COLORS, + reinterpret_cast<void **>(&bit_ptr), + NULL, 0)); + + SelectObject(mem_hdc, bitmap); + // Clear the bitmap to white (so that rounded corners on windows + // show up on a white background, and strangely-shaped windows + // look reasonable). Not capturing an alpha mask saves a + // bit of space. + PatBlt(mem_hdc, 0, 0, width, height, WHITENESS); + // Grab a copy of the window + // First, see if PrintWindow is defined (it's not in Windows 2000). + typedef BOOL (WINAPI *PrintWindowPointer)(HWND, HDC, UINT); + PrintWindowPointer print_window = + reinterpret_cast<PrintWindowPointer>( + GetProcAddress(GetModuleHandle(L"User32.dll"), "PrintWindow")); + + // If PrintWindow is defined, use it. It will work on partially + // obscured windows, and works better for out of process sub-windows. + // Otherwise grab the bits we can get with BitBlt; it's better + // than nothing and will work fine in the average case (window is + // completely on screen). + if (print_window) + (*print_window)(window_handle, mem_hdc, 0); + else + BitBlt(mem_hdc, 0, 0, width, height, window_hdc, 0, 0, SRCCOPY); + + // We now have a copy of the window contents in a DIB, so + // encode it into a useful format for posting to the bug report + // server. + gfx::PNGCodec::Encode(bit_ptr, gfx::PNGCodec::FORMAT_BGRA, + width, height, width * 4, true, + png_representation); + + ReleaseDC(window_handle, window_hdc); +} + +bool IsWindowActive(HWND hwnd) { + WINDOWINFO info; + return ::GetWindowInfo(hwnd, &info) && + ((info.dwWindowStatus & WS_ACTIVECAPTION) != 0); +} + +bool IsReservedName(const string16& filename) { + // This list is taken from the MSDN article "Naming a file" + // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx + // I also added clock$ because GetSaveFileName seems to consider it as a + // reserved name too. + static const wchar_t* const known_devices[] = { + L"con", L"prn", L"aux", L"nul", L"com1", L"com2", L"com3", L"com4", L"com5", + L"com6", L"com7", L"com8", L"com9", L"lpt1", L"lpt2", L"lpt3", L"lpt4", + L"lpt5", L"lpt6", L"lpt7", L"lpt8", L"lpt9", L"clock$" + }; + string16 filename_lower = StringToLowerASCII(filename); + + for (int i = 0; i < arraysize(known_devices); ++i) { + // Exact match. + if (filename_lower == known_devices[i]) + return true; + // Starts with "DEVICE.". + if (filename_lower.find(string16(known_devices[i]) + L".") == 0) + return true; + } + + static const wchar_t* const magic_names[] = { + // These file names are used by the "Customize folder" feature of the shell. + L"desktop.ini", + L"thumbs.db", + }; + + for (int i = 0; i < arraysize(magic_names); ++i) { + if (filename_lower == magic_names[i]) + return true; + } + + return false; +} + +// In addition to passing the RTL flags to ::MessageBox if we are running in an +// RTL locale, we need to make sure that LTR strings are rendered correctly by +// adding the appropriate Unicode directionality marks. +int MessageBox(HWND hwnd, + const string16& text, + const string16& caption, + UINT flags) { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoMessageBox)) + return IDOK; + + UINT actual_flags = flags; + if (base::i18n::IsRTL()) + actual_flags |= MB_RIGHT | MB_RTLREADING; + + string16 localized_text = text; + base::i18n::AdjustStringForLocaleDirection(&localized_text); + const wchar_t* text_ptr = localized_text.c_str(); + + string16 localized_caption = caption; + base::i18n::AdjustStringForLocaleDirection(&localized_caption); + const wchar_t* caption_ptr = localized_caption.c_str(); + + return ::MessageBox(hwnd, text_ptr, caption_ptr, actual_flags); +} + +gfx::Font GetWindowTitleFont() { + NONCLIENTMETRICS ncm; + base::win::GetNonClientMetrics(&ncm); + l10n_util::AdjustUIFont(&(ncm.lfCaptionFont)); + base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont))); + return gfx::Font(caption_font); +} + +} // namespace win +} // namespace app diff --git a/app/win/win_util.h b/app/win/win_util.h new file mode 100644 index 0000000..71b0f78 --- /dev/null +++ b/app/win/win_util.h @@ -0,0 +1,114 @@ +// Copyright (c) 2010 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 APP_WIN_WIN_UTIL_H_ +#define APP_WIN_WIN_UTIL_H_ +#pragma once + +#include <windows.h> + +#include <vector> + +#include "base/string16.h" + +class FilePath; + +namespace gfx { +class Font; +class Rect; +} + +namespace app { +namespace win { + +// Creates a string interpretation of the time of day represented by the given +// SYSTEMTIME that's appropriate for the user's default locale. +// Format can be an empty string (for the default format), or a "format picture" +// as specified in the Windows documentation for GetTimeFormat(). +string16 FormatSystemTime(const SYSTEMTIME& time, + const string16& format); + +// Creates a string interpretation of the date represented by the given +// SYSTEMTIME that's appropriate for the user's default locale. +// Format can be an empty string (for the default format), or a "format picture" +// as specified in the Windows documentation for GetDateFormat(). +string16 FormatSystemDate(const SYSTEMTIME& date, + const string16& format); + +// Returns the long path name given a short path name. A short path name +// is a path that follows the 8.3 convention and has ~x in it. If the +// path is already a long path name, the function returns the current +// path without modification. +bool ConvertToLongPath(const string16& short_path, string16* long_path); + +// Returns true if the current point is close enough to the origin point in +// space and time that it would be considered a double click. +bool IsDoubleClick(const POINT& origin, + const POINT& current, + DWORD elapsed_time); + +// Returns true if the current point is far enough from the origin that it +// would be considered a drag. +bool IsDrag(const POINT& origin, const POINT& current); + +// Returns true if edge |edge| (one of ABE_LEFT, TOP, RIGHT, or BOTTOM) of +// monitor |monitor| has an auto-hiding taskbar that's always-on-top. +bool EdgeHasTopmostAutoHideTaskbar(UINT edge, HMONITOR monitor); + +// Duplicates a section handle from another process to the current process. +// Returns the new valid handle if the function succeed. NULL otherwise. +HANDLE GetSectionFromProcess(HANDLE section, HANDLE process, bool read_only); + +// Duplicates a section handle from the current process for use in another +// process. Returns the new valid handle or NULL on failure. +HANDLE GetSectionForProcess(HANDLE section, HANDLE process, bool read_only); + +// Adjusts the value of |child_rect| if necessary to ensure that it is +// completely visible within |parent_rect|. +void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect, + gfx::Rect* child_rect, + int padding); + +// Returns the bounds for the monitor that contains the largest area of +// intersection with the specified rectangle. +gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect); + +// Returns true if the virtual key code is a digit coming from the numeric +// keypad (with or without NumLock on). |extended_key| should be set to the +// extended key flag specified in the WM_KEYDOWN/UP where the |key_code| +// originated. +bool IsNumPadDigit(int key_code, bool extended_key); + +// Grabs a snapshot of the designated window and stores a PNG representation +// into a byte vector. +void GrabWindowSnapshot(HWND window_handle, + std::vector<unsigned char>* png_representation); + +// Returns whether the specified window is the current active window. +bool IsWindowActive(HWND hwnd); + +// Returns whether the specified file name is a reserved name on windows. +// This includes names like "com2.zip" (which correspond to devices) and +// desktop.ini and thumbs.db which have special meaning to the windows shell. +bool IsReservedName(const string16& filename); + +// A wrapper around Windows' MessageBox function. Using a Chrome specific +// MessageBox function allows us to control certain RTL locale flags so that +// callers don't have to worry about adding these flags when running in a +// right-to-left locale. +int MessageBox(HWND hwnd, + const string16& text, + const string16& caption, + UINT flags); + +// Returns the system set window title font. +gfx::Font GetWindowTitleFont(); + +// The thickness of an auto-hide taskbar in pixels. +extern const int kAutoHideTaskbarThicknessPx; + +} // namespace win +} // namespace app + +#endif // APP_WIN_WIN_UTIL_H_ diff --git a/app/win/win_util_unittest.cc b/app/win/win_util_unittest.cc new file mode 100644 index 0000000..0dc4568 --- /dev/null +++ b/app/win/win_util_unittest.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2010 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 "app/win/win_util.h" +#include "gfx/rect.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace app { +namespace win { + +TEST(WinUtilTest, EnsureRectIsVisibleInRect) { + gfx::Rect parent_rect(0, 0, 500, 400); + + { + // Child rect x < 0 + gfx::Rect child_rect(-50, 20, 100, 100); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(10, 20, 100, 100), child_rect); + } + + { + // Child rect y < 0 + gfx::Rect child_rect(20, -50, 100, 100); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(20, 10, 100, 100), child_rect); + } + + { + // Child rect right > parent_rect.right + gfx::Rect child_rect(450, 20, 100, 100); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(390, 20, 100, 100), child_rect); + } + + { + // Child rect bottom > parent_rect.bottom + gfx::Rect child_rect(20, 350, 100, 100); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(20, 290, 100, 100), child_rect); + } + + { + // Child rect width > parent_rect.width + gfx::Rect child_rect(20, 20, 700, 100); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(20, 20, 480, 100), child_rect); + } + + { + // Child rect height > parent_rect.height + gfx::Rect child_rect(20, 20, 100, 700); + EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10); + EXPECT_EQ(gfx::Rect(20, 20, 100, 380), child_rect); + } +} + +} // namespace win +} // namespace app |