diff options
Diffstat (limited to 'app/win')
-rw-r--r-- | app/win/hwnd_util.cc | 124 | ||||
-rw-r--r-- | app/win/hwnd_util.h | 20 | ||||
-rw-r--r-- | app/win/shell.cc | 112 | ||||
-rw-r--r-- | app/win/shell.h | 41 |
4 files changed, 297 insertions, 0 deletions
diff --git a/app/win/hwnd_util.cc b/app/win/hwnd_util.cc index b0be404..30b7395 100644 --- a/app/win/hwnd_util.cc +++ b/app/win/hwnd_util.cc @@ -4,11 +4,49 @@ #include "app/win/hwnd_util.h" +#include <dwmapi.h> + #include "base/string_util.h" +#include "base/win/windows_version.h" +#include "gfx/rect.h" +#include "gfx/size.h" + +#pragma comment(lib, "dwmapi.lib") namespace app { namespace win { +namespace { + +// Adjust the window to fit, returning true if the window was resized or moved. +bool AdjustWindowToFit(HWND hwnd, const RECT& bounds) { + // Get the monitor. + HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST); + if (!hmon) { + NOTREACHED() << "Unable to find default monitor"; + // No monitor available. + return false; + } + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hmon, &mi); + gfx::Rect window_rect(bounds); + gfx::Rect monitor_rect(mi.rcWork); + gfx::Rect new_window_rect = window_rect.AdjustToFit(monitor_rect); + if (!new_window_rect.Equals(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 true; + } else { + return false; + } +} + +} // 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 @@ -55,5 +93,91 @@ void* GetWindowUserData(HWND hwnd) { #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 gfx::Size& pref, + bool pref_is_client) { + 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); + } else { + // No parent. Center over the monitor the window is on. + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST); + if (monitor) { + MONITORINFO mi = {0}; + mi.cbSize = sizeof(mi); + GetMonitorInfo(monitor, &mi); + center_bounds = mi.rcWork; + } else { + NOTREACHED() << "Unable to get default monitor"; + } + } + window_bounds.left = center_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 + + (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(); + } + + // Get the WINDOWINFO for window. We need the style to calculate the size + // for the window. + WINDOWINFO win_info = {0}; + win_info.cbSize = sizeof(WINDOWINFO); + GetWindowInfo(window, &win_info); + + // Calculate the window size needed for the content size. + + if (!pref_is_client || + AdjustWindowRectEx(&window_bounds, win_info.dwStyle, FALSE, + win_info.dwExStyle)) { + if (!AdjustWindowToFit(window, window_bounds)) { + // The window fits, reset the bounds. + SetWindowPos(window, 0, window_bounds.left, window_bounds.top, + window_bounds.right - window_bounds.left, + window_bounds.bottom - window_bounds.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } // else case, AdjustWindowToFit set the bounds for us. + } else { + NOTREACHED() << "Unable to adjust window to fit"; + } +} + +bool ShouldUseVistaFrame() { + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return false; + // If composition is not enabled, we behave like on XP. + BOOL f; + DwmIsCompositionEnabled(&f); + return !!f; +} + } // namespace win } // namespace app diff --git a/app/win/hwnd_util.h b/app/win/hwnd_util.h index f8ae37e..bace47e 100644 --- a/app/win/hwnd_util.h +++ b/app/win/hwnd_util.h @@ -10,6 +10,10 @@ #include "base/string16.h" +namespace gfx { +class Size; +} + namespace app { namespace win { @@ -25,6 +29,22 @@ WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc); void* SetWindowUserData(HWND hwnd, void* user_data); void* GetWindowUserData(HWND hwnd); +// Returns true if the specified window is the current active top window or one +// of its children. +bool DoesWindowBelongToActiveWindow(HWND window); + +// Sizes the window to have a client or window size (depending on the value of +// |pref_is_client|) of pref, then centers the window over parent, ensuring the +// window fits on screen. +void CenterAndSizeWindow(HWND parent, + HWND window, + const gfx::Size& pref, + bool pref_is_client); + +// Returns true if we are on Windows Vista or greater and composition is +// enabled. +bool ShouldUseVistaFrame(); + } // namespace win } // namespace app diff --git a/app/win/shell.cc b/app/win/shell.cc new file mode 100644 index 0000000..a3c7331 --- /dev/null +++ b/app/win/shell.cc @@ -0,0 +1,112 @@ +// 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/shell.h" + +#include <shellapi.h> +#include <shlobj.h> + +#include "base/file_path.h" +#include "base/native_library.h" +#include "base/string_util.h" +#include "base/win/scoped_comptr.h" +#include "base/win/windows_version.h" +#include "base/win_util.h" + +namespace app { +namespace win { + +namespace { + +const wchar_t kShell32[] = L"shell32.dll"; +const char kSHGetPropertyStoreForWindow[] = "SHGetPropertyStoreForWindow"; + +// Define the type of SHGetPropertyStoreForWindow is SHGPSFW. +typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *SHGPSFW)(HWND hwnd, + REFIID riid, + void** ppv); + +} // namespace + +// Open an item via a shell execute command. Error code checking and casting +// explanation: http://msdn2.microsoft.com/en-us/library/ms647732.aspx +bool OpenItemViaShell(const FilePath& full_path) { + HINSTANCE h = ::ShellExecuteW( + NULL, NULL, full_path.value().c_str(), NULL, + full_path.DirName().value().c_str(), SW_SHOWNORMAL); + + LONG_PTR error = reinterpret_cast<LONG_PTR>(h); + if (error > 32) + return true; + + if ((error == SE_ERR_NOASSOC)) + return OpenItemWithExternalApp(full_path.value()); + + return false; +} + +bool OpenItemViaShellNoZoneCheck(const FilePath& full_path) { + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.fMask = SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = NULL; + sei.lpFile = full_path.value().c_str(); + if (::ShellExecuteExW(&sei)) + return true; + LONG_PTR error = reinterpret_cast<LONG_PTR>(sei.hInstApp); + if ((error == SE_ERR_NOASSOC)) + return OpenItemWithExternalApp(full_path.value()); + return false; +} + +// Show the Windows "Open With" dialog box to ask the user to pick an app to +// open the file with. +bool OpenItemWithExternalApp(const string16& full_path) { + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.fMask = SEE_MASK_FLAG_DDEWAIT; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"openas"; + sei.lpFile = full_path.c_str(); + return (TRUE == ::ShellExecuteExW(&sei)); +} + +void SetAppIdForWindow(const string16& app_id, HWND hwnd) { + // This functionality is only available on Win7+. + if (base::win::GetVersion() < base::win::VERSION_WIN7) + return; + + // Load Shell32.dll into memory. + // TODO(brg): Remove this mechanism when the Win7 SDK is available in trunk. + std::wstring shell32_filename(kShell32); + FilePath shell32_filepath(shell32_filename); + base::NativeLibrary shell32_library = base::LoadNativeLibrary( + shell32_filepath); + + if (!shell32_library) + return; + + // Get the function pointer for SHGetPropertyStoreForWindow. + void* function = base::GetFunctionPointerFromNativeLibrary( + shell32_library, + kSHGetPropertyStoreForWindow); + + if (!function) { + base::UnloadNativeLibrary(shell32_library); + return; + } + + // Set the application's name. + base::win::ScopedComPtr<IPropertyStore> pps; + SHGPSFW SHGetPropertyStoreForWindow = static_cast<SHGPSFW>(function); + HRESULT result = SHGetPropertyStoreForWindow( + hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive())); + if (S_OK == result) + win_util::SetAppIdForPropertyStore(pps, app_id.c_str()); + + // Cleanup. + base::UnloadNativeLibrary(shell32_library); +} + +} // namespace win +} // namespace app diff --git a/app/win/shell.h b/app/win/shell.h new file mode 100644 index 0000000..44ee3ba7 --- /dev/null +++ b/app/win/shell.h @@ -0,0 +1,41 @@ +// 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_SHELL_H_ +#define APP_WIN_SHELL_H_ + +#include <windows.h> + +#include "base/string16.h" + +class FilePath; + +namespace app { +namespace win { + +// Open or run a file via the Windows shell. In the event that there is no +// default application registered for the file specified by 'full_path', +// ask the user, via the Windows "Open With" dialog. +// Returns 'true' on successful open, 'false' otherwise. +bool OpenItemViaShell(const FilePath& full_path); + +// The download manager now writes the alternate data stream with the +// zone on all downloads. This function is equivalent to OpenItemViaShell +// without showing the zone warning dialog. +bool OpenItemViaShellNoZoneCheck(const FilePath& full_path); + +// Ask the user, via the Windows "Open With" dialog, for an application to use +// to open the file specified by 'full_path'. +// Returns 'true' on successful open, 'false' otherwise. +bool OpenItemWithExternalApp(const string16& full_path); + +// Sets the application id given as the Application Model ID for the window +// specified. This method is used to insure that different web applications +// do not group together on the Win7 task bar. +void SetAppIdForWindow(const string16& app_id, HWND hwnd); + +} // namespace win +} // namespace app + +#endif // APP_WIN_SHELL_H_ |