diff options
author | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-06 03:47:09 +0000 |
---|---|---|
committer | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-06 03:47:09 +0000 |
commit | ce44e51e5e0b29d3ad202777076fc29acfd0e08e (patch) | |
tree | 43c80c390781b28f3134e1ee2382ac79c34cbe3f /chrome/browser/aeropeek_manager.cc | |
parent | 5afcaebec9a22d54a71ce4302afb020d6cc652e5 (diff) | |
download | chromium_src-ce44e51e5e0b29d3ad202777076fc29acfd0e08e.zip chromium_src-ce44e51e5e0b29d3ad202777076fc29acfd0e08e.tar.gz chromium_src-ce44e51e5e0b29d3ad202777076fc29acfd0e08e.tar.bz2 |
Remove Aero Peek Tabs code.
BUG=8036
TEST=Checked --enable-aero-peek-tabs does not take effect
Review URL: http://codereview.chromium.org/10368027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/aeropeek_manager.cc')
-rw-r--r-- | chrome/browser/aeropeek_manager.cc | 1031 |
1 files changed, 0 insertions, 1031 deletions
diff --git a/chrome/browser/aeropeek_manager.cc b/chrome/browser/aeropeek_manager.cc deleted file mode 100644 index e00242a..0000000 --- a/chrome/browser/aeropeek_manager.cc +++ /dev/null @@ -1,1031 +0,0 @@ -// 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 "chrome/browser/aeropeek_manager.h" - -#include <dwmapi.h> -#include <shobjidl.h> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/scoped_native_library.h" -#include "base/synchronization/waitable_event.h" -#include "base/win/scoped_comptr.h" -#include "base/win/scoped_gdi_object.h" -#include "base/win/scoped_hdc.h" -#include "base/win/windows_version.h" -#include "chrome/browser/app_icon_win.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/favicon/favicon_tab_helper.h" -#include "chrome/browser/sessions/restore_tab_helper.h" -#include "chrome/browser/tab_contents/thumbnail_generator.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/installer/util/browser_distribution.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host_view.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_delegate.h" -#include "content/public/browser/web_contents_view.h" -#include "skia/ext/image_operations.h" -#include "skia/ext/platform_canvas.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/win/shell.h" -#include "ui/base/win/window_impl.h" -#include "ui/gfx/gdi_util.h" -#include "ui/gfx/icon_util.h" -#include "ui/views/widget/native_widget_win.h" - -#pragma comment(lib, "dwmapi.lib") - -using content::BrowserThread; -using content::WebContents; - -namespace { - -// Sends a thumbnail bitmap to Windows. Windows assumes this function is called -// when a WM_DWMSENDICONICTHUMBNAIL message sent to a place-holder window. We -// can use DwmInvalidateIconicBitmap() to force Windows to send the message. -HRESULT CallDwmSetIconicThumbnail(HWND window, HBITMAP bitmap, DWORD flags) { - FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi")); - base::ScopedNativeLibrary dwmapi(dwmapi_path); - - typedef HRESULT (STDAPICALLTYPE *DwmSetIconicThumbnailProc)( - HWND, HBITMAP, DWORD); - DwmSetIconicThumbnailProc dwm_set_iconic_thumbnail = - static_cast<DwmSetIconicThumbnailProc>( - dwmapi.GetFunctionPointer("DwmSetIconicThumbnail")); - - if (!dwm_set_iconic_thumbnail) - return E_FAIL; - - return dwm_set_iconic_thumbnail(window, bitmap, flags); -} - -// Sends a preview bitmap to Windows. Windows assumes this function is called -// when a WM_DWMSENDICONICLIVEPREVIEWBITMAP message sent to a place-holder -// window. -HRESULT CallDwmSetIconicLivePreviewBitmap(HWND window, - HBITMAP bitmap, - POINT* client, - DWORD flags) { - FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi")); - base::ScopedNativeLibrary dwmapi(dwmapi_path); - - typedef HRESULT (STDAPICALLTYPE *DwmSetIconicLivePreviewBitmapProc)( - HWND, HBITMAP, POINT*, DWORD); - DwmSetIconicLivePreviewBitmapProc dwm_set_live_preview_bitmap = - static_cast<DwmSetIconicLivePreviewBitmapProc>( - dwmapi.GetFunctionPointer("DwmSetIconicLivePreviewBitmap")); - - if (!dwm_set_live_preview_bitmap) - return E_FAIL; - - return dwm_set_live_preview_bitmap(window, bitmap, client, flags); -} - -// Invalidates the thumbnail image of the specified place-holder window. (See -// the comments in CallDwmSetIconicThumbnai()). -HRESULT CallDwmInvalidateIconicBitmaps(HWND window) { - FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi")); - base::ScopedNativeLibrary dwmapi(dwmapi_path); - - typedef HRESULT (STDAPICALLTYPE *DwmInvalidateIconicBitmapsProc)(HWND); - DwmInvalidateIconicBitmapsProc dwm_invalidate_iconic_bitmaps = - static_cast<DwmInvalidateIconicBitmapsProc>( - dwmapi.GetFunctionPointer("DwmInvalidateIconicBitmaps")); - - if (!dwm_invalidate_iconic_bitmaps) - return E_FAIL; - - return dwm_invalidate_iconic_bitmaps(window); -} - -void CopyFromBackingStoreComplete(bool* result, bool* done, bool succeeded) { - *result = succeeded; - *done = true; -} - -} // namespace - -namespace { - -// These callbacks indirectly access the specified tab through the -// AeroPeekWindowDelegate interface to prevent these tasks from accessing the -// deleted tabs. - -// A callback that registers a thumbnail window as a child of the specified -// browser application. -void RegisterThumbnailCallback(HWND frame_window, HWND window, bool active) { - // Set the App ID of the browser for this place-holder window to tell - // that this window is a child of the browser application, i.e. to tell - // that this thumbnail window should be displayed when we hover the - // browser icon in the taskbar. - // TODO(mattm): This should use ShellIntegration::GetChromiumAppId to work - // properly with multiple profiles. - ui::win::SetAppIdForWindow( - BrowserDistribution::GetDistribution()->GetBrowserAppId(), window); - - // Register this place-holder window to the taskbar as a child of - // the browser window and add it to the end of its tab list. - // Correctly, this registration should be called after this browser window - // receives a registered window message "TaskbarButtonCreated", which - // means that Windows creates a taskbar button for this window in its - // taskbar. But it seems to be OK to register it without checking the - // message. - // TODO(hbono): we need to check this registered message? - base::win::ScopedComPtr<ITaskbarList3> taskbar; - if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL, - CLSCTX_INPROC_SERVER)) || - FAILED(taskbar->HrInit()) || - FAILED(taskbar->RegisterTab(window, frame_window)) || - FAILED(taskbar->SetTabOrder(window, NULL))) - return; - if (active) - taskbar->SetTabActive(window, frame_window, 0); -} - -// Calculates the thumbnail size sent to Windows so we can preserve the pixel -// aspect-ratio of the source bitmap. Since Windows returns an error when we -// send an image bigger than the given size, we decrease either the thumbnail -// width or the thumbnail height so we can fit the longer edge of the source -// window. -void GetThumbnailSize(const gfx::Size& aeropeek_size, int width, int height, - gfx::Size* output) { - float thumbnail_width = static_cast<float>(aeropeek_size.width()); - float thumbnail_height = static_cast<float>(aeropeek_size.height()); - float source_width = static_cast<float>(width); - float source_height = static_cast<float>(height); - DCHECK(source_width && source_height); - - float ratio_width = thumbnail_width / source_width; - float ratio_height = thumbnail_height / source_height; - if (ratio_width > ratio_height) { - thumbnail_width = source_width * ratio_height; - } else { - thumbnail_height = source_height * ratio_width; - } - - output->set_width(static_cast<int>(thumbnail_width)); - output->set_height(static_cast<int>(thumbnail_height)); -} - -// Returns a pixel of the specified bitmap. If this bitmap is a dummy bitmap, -// this function returns an opaque white pixel instead. -int GetPixel(const SkBitmap& bitmap, int x, int y) { - const int* tab_pixels = reinterpret_cast<const int*>(bitmap.getPixels()); - if (!tab_pixels) - return 0xFFFFFFFF; - return tab_pixels[y * bitmap.width() + x]; -} - -// A callback which creates a thumbnail image used by AeroPeek and sends it to -// Windows. -void SendThumbnailCallback( - HWND aeropeek_window, const gfx::Rect& content_bounds, - const gfx::Size& aeropeek_size, const SkBitmap& tab_bitmap, - base::WaitableEvent* ready) { - // Calculate the size of the aeropeek thumbnail and resize the tab bitmap - // to the size. When the given bitmap is an empty bitmap, we create a dummy - // bitmap from the content-area rectangle to create a DIB. (We don't need to - // allocate pixels for this case since we don't use them.) - gfx::Size thumbnail_size; - SkBitmap thumbnail_bitmap; - - if (tab_bitmap.isNull() || tab_bitmap.empty()) { - GetThumbnailSize( - aeropeek_size, content_bounds.width(), content_bounds.height(), - &thumbnail_size); - - thumbnail_bitmap.setConfig(SkBitmap::kARGB_8888_Config, - thumbnail_size.width(), thumbnail_size.height()); - } else { - GetThumbnailSize(aeropeek_size, tab_bitmap.width(), tab_bitmap.height(), - &thumbnail_size); - - thumbnail_bitmap = skia::ImageOperations::Resize( - tab_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, - thumbnail_size.width(), thumbnail_size.height()); - } - - // Create a DIB, copy the resized image, and send the DIB to Windows. - // We can delete this DIB after sending it to Windows since Windows creates - // a copy of the DIB and use it. - base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL)); - if (!hdc.Get()) { - LOG(ERROR) << "cannot create a memory DC: " << GetLastError(); - return; - } - - BITMAPINFOHEADER header; - gfx::CreateBitmapHeader(thumbnail_size.width(), thumbnail_size.height(), - &header); - - void* bitmap_data = NULL; - base::win::ScopedBitmap bitmap( - CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&header), - DIB_RGB_COLORS, &bitmap_data, NULL, 0)); - - if (!bitmap.Get() || !bitmap_data) { - LOG(ERROR) << "cannot create a bitmap: " << GetLastError(); - return; - } - - SkAutoLockPixels lock(thumbnail_bitmap); - int* content_pixels = reinterpret_cast<int*>(bitmap_data); - for (int y = 0; y < thumbnail_size.height(); ++y) { - for (int x = 0; x < thumbnail_size.width(); ++x) { - content_pixels[y * thumbnail_size.width() + x] = - GetPixel(thumbnail_bitmap, x, y); - } - } - - HRESULT result = CallDwmSetIconicThumbnail(aeropeek_window, bitmap, 0); - if (FAILED(result)) - LOG(ERROR) << "cannot set a tab thumbnail: " << result; - - ready->Signal(); -} - -int GetTabPixel(const SkBitmap& tab_bitmap, int x, int y) { - // Return the opaque while pixel to prevent old foreground tab from being - // shown when we cannot get the specified pixel. - const int* tab_pixels = reinterpret_cast<int*>(tab_bitmap.getPixels()); - if (!tab_pixels || x >= tab_bitmap.width() || y >= tab_bitmap.height()) - return 0xFFFFFFFF; - - // DWM uses alpha values to distinguish opaque colors and transparent ones. - // Set the alpha value of this source pixel to prevent the original window - // from being shown through. - return 0xFF000000 | tab_pixels[y * tab_bitmap.width() + x]; -} - -// A task which creates a preview image used by AeroPeek and sends it to -// Windows. -// This task becomes more complicated than SendThumbnailTask because this task -// calculates the rectangle of the user-perceived content area (infobars + -// content area) so Windows can paste the preview image on it. -// This task is used if an AeroPeek window receives a -// WM_DWMSENDICONICLIVEPREVIEWBITMAP message. -void SendLivePreviewCallback( - HWND aeropeek_window, const gfx::Rect& content_bounds, - const SkBitmap& tab_bitmap) { - // Create a DIB for the user-perceived content area of the tab, copy the - // tab image into the DIB, and send it to Windows. - // We don't need to paste this tab image onto the frame image since Windows - // automatically pastes it for us. - base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL)); - if (!hdc.Get()) { - LOG(ERROR) << "cannot create a memory DC: " << GetLastError(); - return; - } - - BITMAPINFOHEADER header; - gfx::CreateBitmapHeader(content_bounds.width(), content_bounds.height(), - &header); - - void* bitmap_data = NULL; - base::win::ScopedBitmap bitmap( - CreateDIBSection(hdc.Get(), reinterpret_cast<BITMAPINFO*>(&header), - DIB_RGB_COLORS, &bitmap_data, NULL, 0)); - if (!bitmap.Get() || !bitmap_data) { - LOG(ERROR) << "cannot create a bitmap: " << GetLastError(); - return; - } - - // Copy the tab image onto the DIB. - SkAutoLockPixels lock(tab_bitmap); - int* content_pixels = reinterpret_cast<int*>(bitmap_data); - for (int y = 0; y < content_bounds.height(); ++y) { - for (int x = 0; x < content_bounds.width(); ++x) - content_pixels[y * content_bounds.width() + x] = - GetTabPixel(tab_bitmap, x, y); - } - - // Send the preview image to Windows. - // We can set its offset to the top left corner of the user-perceived - // content area so Windows can paste this bitmap onto the correct - // position. - POINT content_offset = {content_bounds.x(), content_bounds.y()}; - HRESULT result = CallDwmSetIconicLivePreviewBitmap( - aeropeek_window, bitmap, &content_offset, 0); - if (FAILED(result)) - LOG(ERROR) << "cannot send a content image: " << result; -} - -} // namespace - -// A class which implements a place-holder window used by AeroPeek. -// The major work of this class are: -// * Updating the status of Tab Thumbnails; -// * Receiving messages from Windows, and; -// * Translating received messages for TabStrip. -// This class is used by the AeroPeekManager class, which is a proxy -// between TabStrip and Windows 7. -class AeroPeekWindow : public ui::WindowImpl { - public: - AeroPeekWindow(HWND frame_window, - AeroPeekWindowDelegate* delegate, - int tab_id, - bool tab_active, - const std::wstring& title, - const SkBitmap& favicon_bitmap); - ~AeroPeekWindow(); - - // Activates or deactivates this window. - // This window uses this information not only for highlighting the selected - // tab when Windows shows the thumbnail list, but also for preventing us - // from rendering AeroPeek images for deactivated windows so often. - void Activate(); - void Deactivate(); - - // Updates the image of this window. - // When the AeroPeekManager class calls this function, this window starts - // a task which updates its thumbnail image. - // NOTE: to prevent sending lots of tasks that update the thumbnail images - // and hurt the system performance, we post a task only when |is_loading| is - // false for non-active tabs. (On the other hand, we always post an update - // task for an active tab as IE8 does.) - void Update(bool is_loading); - - // Destroys this window. - // This function removes this window from the thumbnail list and deletes - // all the resources attached to this window, i.e. this object is not valid - // any longer after calling this function. - void Destroy(); - - // Updates the title of this window. - // This function just sends a WM_SETTEXT message to update the window title. - void SetTitle(const std::wstring& title); - - // Updates the icon used for AeroPeek. Unlike SetTitle(), this function just - // saves a copy of the given bitmap since it takes time to create a Windows - // icon from this bitmap set it as the window icon. We will create a Windows - // when Windows sends a WM_GETICON message to retrieve it. - void SetFavicon(const SkBitmap& favicon); - - // Returns the tab ID associated with this window. - int tab_id() { return tab_id_; } - - // Message handlers. - BEGIN_MSG_MAP_EX(TabbedThumbnailWindow) - MESSAGE_HANDLER_EX(WM_DWMSENDICONICTHUMBNAIL, OnDwmSendIconicThumbnail) - MESSAGE_HANDLER_EX(WM_DWMSENDICONICLIVEPREVIEWBITMAP, - OnDwmSendIconicLivePreviewBitmap) - - MSG_WM_ACTIVATE(OnActivate) - MSG_WM_CLOSE(OnClose) - MSG_WM_CREATE(OnCreate) - MSG_WM_GETICON(OnGetIcon) - END_MSG_MAP() - - private: - // Updates the thumbnail image of this window. - // This function is a wrapper function of CallDwmInvalidateIconicBitmaps() - // but it invalidates the thumbnail only when |ready_| is signaled to prevent - // us from posting two or more tasks. - void UpdateThumbnail(); - - // Returns the user-perceived content area. - gfx::Rect GetContentBounds() const; - - // Message-handler functions. - // Called when a window has been created. - LRESULT OnCreate(LPCREATESTRUCT create_struct); - - // Called when this thumbnail window is activated, i.e. a user clicks this - // thumbnail window. - void OnActivate(UINT action, BOOL minimized, HWND window); - - // Called when this thumbnail window is closed, i.e. a user clicks the close - // button of this thumbnail window. - void OnClose(); - - // Called when Windows needs a thumbnail image for this thumbnail window. - // Windows can send a WM_DWMSENDICONICTHUMBNAIL message anytime when it - // needs the thumbnail bitmap for this place-holder window (e.g. when we - // register this place-holder window to Windows, etc.) - // When this window receives a WM_DWMSENDICONICTHUMBNAIL message, it HAS TO - // create a thumbnail bitmap and send it to Windows through a - // DwmSendIconicThumbnail() call. (Windows shows a "page-loading" animation - // while it waits for a thumbnail bitmap.) - LRESULT OnDwmSendIconicThumbnail(UINT message, - WPARAM wparam, - LPARAM lparam); - - // Called when Windows needs a preview image for this thumbnail window. - // Same as above, Windows can send a WM_DWMSENDICONICLIVEPREVIEWBITMAP - // message anytime when it needs a preview bitmap and we have to create and - // send the bitmap when it needs it. - LRESULT OnDwmSendIconicLivePreviewBitmap(UINT message, - WPARAM wparam, - LPARAM lparam); - - // Called when Windows needs an icon for this thumbnail window. - // Windows sends a WM_GETICON message with ICON_SMALL when it needs an - // AeroPeek icon. we handle WM_GETICON messages by ourselves so we can create - // a custom icon from a favicon only when Windows need it. - HICON OnGetIcon(UINT index); - - private: - // An application window which owns this tab. - // We show this thumbnail image of this window when a user hovers a mouse - // cursor onto the taskbar icon of this application window. - HWND frame_window_; - - // An interface which dispatches events received from Window. - // This window notifies events received from Windows to TabStrip through - // this interface. - // We should not directly access WebContents members since Windows may send - // AeroPeek events to a tab closed by Chrome. - // To prevent such race condition, we get access to WebContents through - // AeroPeekManager. - AeroPeekWindowDelegate* delegate_; - - // A tab ID associated with this window. - int tab_id_; - - // A flag that represents whether or not this tab is active. - // This flag is used for preventing us from updating the thumbnail images - // when this window is not active. - bool tab_active_; - - // An event that represents whether or not we can post a task which updates - // the thumbnail image of this window. - // We post a task only when this event is signaled. - base::WaitableEvent ready_to_update_thumbnail_; - - // The title of this tab. - std::wstring title_; - - // The favicon for this tab. - SkBitmap favicon_bitmap_; - base::win::ScopedHICON favicon_; - - // The icon used by the frame window. - // This icon is used when this tab doesn't have a favicon. - HICON frame_icon_; - - DISALLOW_COPY_AND_ASSIGN(AeroPeekWindow); -}; - -AeroPeekWindow::AeroPeekWindow(HWND frame_window, - AeroPeekWindowDelegate* delegate, - int tab_id, - bool tab_active, - const std::wstring& title, - const SkBitmap& favicon_bitmap) - : frame_window_(frame_window), - delegate_(delegate), - tab_id_(tab_id), - tab_active_(tab_active), - ready_to_update_thumbnail_(false, true), - title_(title), - favicon_bitmap_(favicon_bitmap), - frame_icon_(NULL) { - // Set the class styles and window styles for this thumbnail window. - // An AeroPeek window should be a tool window. (Otherwise, - // Windows doesn't send WM_DWMSENDICONICTHUMBNAIL messages.) - set_initial_class_style(0); - set_window_style(WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION); - set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE); -} - -AeroPeekWindow::~AeroPeekWindow() { -} - -void AeroPeekWindow::Activate() { - tab_active_ = true; - - // Create a place-holder window and add it to the tab list if it has not been - // created yet. (This case happens when we re-attached a detached window.) - if (!IsWindow(hwnd())) { - Update(false); - return; - } - - // Notify Windows to set the thumbnail focus to this window. - base::win::ScopedComPtr<ITaskbarList3> taskbar; - HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, - CLSCTX_INPROC_SERVER); - if (FAILED(result)) { - LOG(ERROR) << "failed creating an ITaskbarList3 interface."; - return; - } - - result = taskbar->HrInit(); - if (FAILED(result)) { - LOG(ERROR) << "failed initializing an ITaskbarList3 interface."; - return; - } - - result = taskbar->ActivateTab(hwnd()); - if (FAILED(result)) { - LOG(ERROR) << "failed activating a thumbnail window."; - return; - } - - // Update the thumbnail image to the up-to-date one. - UpdateThumbnail(); -} - -void AeroPeekWindow::Deactivate() { - tab_active_ = false; -} - -void AeroPeekWindow::Update(bool is_loading) { - // Create a place-holder window used by AeroPeek if it has not been created - // so Windows can send events used by AeroPeek to this window. - // Windows automatically sends a WM_DWMSENDICONICTHUMBNAIL message after this - // window is registered to Windows. So, we don't have to invalidate the - // thumbnail image of this window now. - if (!hwnd()) { - gfx::Rect bounds; - WindowImpl::Init(frame_window_, bounds); - return; - } - - // Invalidate the thumbnail image of this window. - // When we invalidate the thumbnail image, we HAVE TO handle a succeeding - // WM_DWMSENDICONICTHUMBNAIL message and update the thumbnail image with a - // DwmSetIconicThumbnail() call. So, we should not call this function when - // we don't have enough information to create a thumbnail. - if (tab_active_ || !is_loading) - UpdateThumbnail(); -} - -void AeroPeekWindow::Destroy() { - if (!IsWindow(hwnd())) - return; - - // Remove this window from the tab list of Windows. - base::win::ScopedComPtr<ITaskbarList3> taskbar; - HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, - CLSCTX_INPROC_SERVER); - if (FAILED(result)) - return; - - result = taskbar->HrInit(); - if (FAILED(result)) - return; - - result = taskbar->UnregisterTab(hwnd()); - - // Destroy this window. - DestroyWindow(hwnd()); -} - -void AeroPeekWindow::SetTitle(const std::wstring& title) { - title_ = title; -} - -void AeroPeekWindow::SetFavicon(const SkBitmap& favicon) { - favicon_bitmap_ = favicon; -} - -void AeroPeekWindow::UpdateThumbnail() { - // We post a task to actually create a new thumbnail. So, this function may - // be called while we are creating a thumbnail. To prevent this window from - // posting two or more tasks, we don't invalidate the current thumbnail - // when this event is not signaled. - if (ready_to_update_thumbnail_.IsSignaled()) - CallDwmInvalidateIconicBitmaps(hwnd()); -} - -gfx::Rect AeroPeekWindow::GetContentBounds() const { - RECT content_rect; - GetClientRect(frame_window_, &content_rect); - - gfx::Insets content_insets; - delegate_->GetContentInsets(&content_insets); - - gfx::Rect content_bounds(content_rect); - content_bounds.Inset(content_insets.left(), - content_insets.top(), - content_insets.right(), - content_insets.bottom()); - return content_bounds; -} - -// message handlers - -void AeroPeekWindow::OnActivate(UINT action, - BOOL minimized, - HWND window) { - // Windows sends a WM_ACTIVATE message not only when a user clicks this - // window (i.e. this window gains the thumbnail focus) but also a user clicks - // another window (i.e. this window loses the thumbnail focus.) - // Return when this window loses the thumbnail focus since we don't have to - // do anything for this case. - if (action == WA_INACTIVE) - return; - - // Ask Chrome to activate the tab associated with this thumbnail window. - // Since TabStripModel calls AeroPeekManager::ActiveTabChanged() when it - // finishes activating the tab. We will move the tab focus of AeroPeek there. - if (delegate_) - delegate_->ActivateTab(tab_id_); -} - -LRESULT AeroPeekWindow::OnCreate(LPCREATESTRUCT create_struct) { - // Initialize the window title now since WindowImpl::Init() always calls - // CreateWindowEx() with its window name NULL. - if (!title_.empty()) { - SendMessage(hwnd(), WM_SETTEXT, 0, - reinterpret_cast<LPARAM>(title_.c_str())); - } - - // Window attributes for DwmSetWindowAttribute(). - // These enum values are copied from Windows SDK 7 so we can compile this - // file with or without it. - // TODO(hbono): Bug 16903: to be deleted when we use Windows SDK 7. - enum { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, - DWMWA_EXTENDED_FRAME_BOUNDS, - DWMWA_HAS_ICONIC_BITMAP, - DWMWA_DISALLOW_PEEK, - DWMWA_EXCLUDED_FROM_PEEK, - DWMWA_LAST - }; - - // Set DWM attributes to tell Windows that this window can provide the - // bitmaps used by AeroPeek. - BOOL force_iconic_representation = TRUE; - DwmSetWindowAttribute(hwnd(), - DWMWA_FORCE_ICONIC_REPRESENTATION, - &force_iconic_representation, - sizeof(force_iconic_representation)); - - BOOL has_iconic_bitmap = TRUE; - DwmSetWindowAttribute(hwnd(), - DWMWA_HAS_ICONIC_BITMAP, - &has_iconic_bitmap, - sizeof(has_iconic_bitmap)); - - // Post a task that registers this thumbnail window to Windows because it - // may take some time. (For example, when we create an ITaskbarList3 - // interface for the first time, Windows loads DLLs and we need to wait for - // some time.) - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&RegisterThumbnailCallback, frame_window_, hwnd(), - tab_active_)); - - return 0; -} - -void AeroPeekWindow::OnClose() { - // Unregister this window from the tab list of Windows and destroy this - // window. - // The resources attached to this object will be deleted when TabStrip calls - // AeroPeekManager::TabClosingAt(). (Please read the comment in TabClosingAt() - // for its details.) - Destroy(); - - // Ask AeroPeekManager to close the tab associated with this thumbnail - // window. - if (delegate_) - delegate_->CloseTab(tab_id_); -} - -LRESULT AeroPeekWindow::OnDwmSendIconicThumbnail(UINT message, - WPARAM wparam, - LPARAM lparam) { - // Update the window title to synchronize the title. - SendMessage(hwnd(), WM_SETTEXT, 0, reinterpret_cast<LPARAM>(title_.c_str())); - - // Create an I/O task since it takes long time to resize these images and - // send them to Windows. This task signals |ready_to_update_thumbnail_| in - // its destructor to notify us when this task has been finished. (We create an - // I/O task even when the given thumbnail is empty to stop the "loading" - // animation.) - DCHECK(delegate_); - - SkBitmap thumbnail; - delegate_->GetTabThumbnail(tab_id_, &thumbnail); - - gfx::Size aeropeek_size(HIWORD(lparam), LOWORD(lparam)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&SendThumbnailCallback, hwnd(), GetContentBounds(), - aeropeek_size, thumbnail, &ready_to_update_thumbnail_)); - return 0; -} - -LRESULT AeroPeekWindow::OnDwmSendIconicLivePreviewBitmap(UINT message, - WPARAM wparam, - LPARAM lparam) { - // Same as OnDwmSendIconicThumbnail(), we create an I/O task which creates - // a preview image used by AeroPeek and send it to Windows. Unlike - // OnDwmSendIconicThumbnail(), we don't have to use events for preventing this - // window from sending two or more tasks because Windows doesn't send - // WM_DWMSENDICONICLIVEPREVIEWBITMAP messages before we send the preview image - // to Windows. - DCHECK(delegate_); - - SkBitmap preview; - delegate_->GetTabPreview(tab_id_, &preview); - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&SendLivePreviewCallback, hwnd(), GetContentBounds(), - preview)); - - return 0; -} - -HICON AeroPeekWindow::OnGetIcon(UINT index) { - // Return the application icon if this window doesn't have favicons. - // We save this application icon to avoid calling LoadIcon() twice or more. - if (favicon_bitmap_.isNull()) { - if (!frame_icon_) { - frame_icon_ = GetAppIcon(); - } - return frame_icon_; - } - - // Create a Windows icon from SkBitmap and send it to Windows. We set this - // icon to the ScopedIcon object to delete it in the destructor. - favicon_.Set(IconUtil::CreateHICONFromSkBitmap(favicon_bitmap_)); - return favicon_.Get(); -} - -AeroPeekManager::AeroPeekManager(HWND application_window) - : application_window_(application_window), - border_left_(0), - border_top_(0), - toolbar_top_(0) { -} - -AeroPeekManager::~AeroPeekManager() { - // Delete all AeroPeekWindow objects. - for (std::list<AeroPeekWindow*>::iterator i = tab_list_.begin(); - i != tab_list_.end(); ++i) { - AeroPeekWindow* window = *i; - delete window; - } -} - -void AeroPeekManager::SetContentInsets(const gfx::Insets& insets) { - content_insets_ = insets; -} - -// static -bool AeroPeekManager::Enabled() { - // We enable our custom AeroPeek only when: - // * Chrome is running on Windows 7 and Aero is enabled, - // * Chrome is not launched in application mode, and - // * Chrome is launched with the "--enable-aero-peek-tabs" option. - // TODO(hbono): Bug 37957 <http://crbug.com/37957>: find solutions that avoid - // flooding users with tab thumbnails. - const CommandLine* command_line = CommandLine::ForCurrentProcess(); - return base::win::GetVersion() >= base::win::VERSION_WIN7 && - views::NativeWidgetWin::IsAeroGlassEnabled() && - !command_line->HasSwitch(switches::kApp) && - command_line->HasSwitch(switches::kEnableAeroPeekTabs); -} - -void AeroPeekManager::DeleteAeroPeekWindow(int tab_id) { - // This function does NOT call AeroPeekWindow::Destroy() before deleting - // the AeroPeekWindow instance. - for (std::list<AeroPeekWindow*>::iterator i = tab_list_.begin(); - i != tab_list_.end(); ++i) { - AeroPeekWindow* window = *i; - if (window->tab_id() == tab_id) { - tab_list_.erase(i); - delete window; - return; - } - } -} - -void AeroPeekManager::DeleteAeroPeekWindowForTab(TabContentsWrapper* tab) { - // Delete the AeroPeekWindow object associated with this tab and all its - // resources. (AeroPeekWindow::Destory() also removes this tab from the tab - // list of Windows.) - AeroPeekWindow* window = GetAeroPeekWindow(GetTabID(tab)); - if (!window) - return; - - window->Destroy(); - DeleteAeroPeekWindow(GetTabID(tab)); -} - -AeroPeekWindow* AeroPeekManager::GetAeroPeekWindow(int tab_id) const { - size_t size = tab_list_.size(); - for (std::list<AeroPeekWindow*>::const_iterator i = tab_list_.begin(); - i != tab_list_.end(); ++i) { - AeroPeekWindow* window = *i; - if (window->tab_id() == tab_id) - return window; - } - return NULL; -} - -void AeroPeekManager::CreateAeroPeekWindowIfNecessary(TabContentsWrapper* tab, - bool foreground) { - if (GetAeroPeekWindow(GetTabID(tab))) - return; - - AeroPeekWindow* window = - new AeroPeekWindow(application_window_, - this, - GetTabID(tab), - foreground, - tab->web_contents()->GetTitle(), - tab->favicon_tab_helper()->GetFavicon()); - tab_list_.push_back(window); -} - -WebContents* AeroPeekManager::GetWebContents(int tab_id) const { - for (TabContentsIterator iterator; !iterator.done(); ++iterator) { - if (GetTabID(*iterator) == tab_id) - return (*iterator)->web_contents(); - } - return NULL; -} - -int AeroPeekManager::GetTabID(TabContentsWrapper* contents) const { - if (!contents) - return -1; - return contents->restore_tab_helper()->session_id().id(); -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroPeekManager, TabStripModelObserver implementation: - -void AeroPeekManager::TabInsertedAt(TabContentsWrapper* contents, - int index, - bool foreground) { - if (!contents) - return; - - CreateAeroPeekWindowIfNecessary(contents, foreground); -} - -void AeroPeekManager::TabDetachedAt(TabContentsWrapper* contents, int index) { - if (!contents) - return; - - // Chrome will call TabInsertedAt() when this tab is inserted to another - // TabStrip. We will re-create an AeroPeekWindow object for this tab and - // re-add it to the tab list there. - DeleteAeroPeekWindowForTab(contents); -} - -void AeroPeekManager::ActiveTabChanged(TabContentsWrapper* old_contents, - TabContentsWrapper* new_contents, - int index, - bool user_gesture) { - // Deactivate the old window in the thumbnail list and activate the new one - // to synchronize the thumbnail list with TabStrip. - if (old_contents) { - AeroPeekWindow* old_window = GetAeroPeekWindow(GetTabID(old_contents)); - if (old_window) - old_window->Deactivate(); - } - - if (new_contents) { - AeroPeekWindow* new_window = GetAeroPeekWindow(GetTabID(new_contents)); - if (new_window) - new_window->Activate(); - } -} - -void AeroPeekManager::TabReplacedAt(TabStripModel* tab_strip_model, - TabContentsWrapper* old_contents, - TabContentsWrapper* new_contents, - int index) { - DeleteAeroPeekWindowForTab(old_contents); - - CreateAeroPeekWindowIfNecessary(new_contents, - (index == tab_strip_model->active_index())); - // We don't need to update the selection as if |new_contents| is selected the - // TabStripModel will send ActiveTabChanged. -} - -void AeroPeekManager::TabMoved(TabContentsWrapper* contents, - int from_index, - int to_index, - bool pinned_state_changed) { - // TODO(hbono): we need to reorder the thumbnail list of Windows here? - // (Unfortunately, it is not so trivial to reorder the thumbnail list when - // we detach/attach tabs.) -} - -void AeroPeekManager::TabChangedAt(TabContentsWrapper* contents, - int index, - TabChangeType change_type) { - if (!contents) - return; - - // Retrieve the AeroPeekWindow object associated with this tab, update its - // title, and post a task that update its thumbnail image if necessary. - AeroPeekWindow* window = GetAeroPeekWindow(GetTabID(contents)); - if (!window) - return; - - // Update the title, the favicon, and the thumbnail used for AeroPeek. - // These function don't actually update the icon and the thumbnail until - // Windows needs them (e.g. when a user hovers a taskbar icon) to avoid - // hurting the rendering performance. (These functions just save the - // information needed for handling update requests from Windows.) - window->SetTitle(contents->web_contents()->GetTitle()); - window->SetFavicon(contents->favicon_tab_helper()->GetFavicon()); - window->Update(contents->web_contents()->IsLoading()); -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroPeekManager, AeroPeekWindowDelegate implementation: - -void AeroPeekManager::ActivateTab(int tab_id) { - // Ask TabStrip to activate this tab. - // We don't have to update thumbnails now since TabStrip will call - // ActiveTabChanged() when it actually activates this tab. - WebContents* contents = GetWebContents(tab_id); - if (contents && contents->GetDelegate()) - contents->GetDelegate()->ActivateContents(contents); -} - -void AeroPeekManager::CloseTab(int tab_id) { - // Ask TabStrip to close this tab. - // TabStrip will call TabClosingAt() when it actually closes this tab. We - // will delete the AeroPeekWindow object attached to this tab there. - WebContents* contents = GetWebContents(tab_id); - if (contents && contents->GetDelegate()) - contents->GetDelegate()->CloseContents(contents); -} - -void AeroPeekManager::GetContentInsets(gfx::Insets* insets) { - *insets = content_insets_; -} - -bool AeroPeekManager::GetTabThumbnail(int tab_id, SkBitmap* thumbnail) { - DCHECK(thumbnail); - - // Copy the thumbnail image and the favicon of this tab. We will resize the - // images and send them to Windows. - WebContents* contents = GetWebContents(tab_id); - if (!contents) - return false; - - ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator(); - DCHECK(generator); - *thumbnail = generator->GetThumbnailForRenderer( - contents->GetRenderViewHost()); - - return true; -} - -bool AeroPeekManager::GetTabPreview(int tab_id, SkBitmap* preview) { - DCHECK(preview); - - // Retrieve the BackingStore associated with the given tab and return its - // SkPlatformCanvas. - WebContents* contents = GetWebContents(tab_id); - if (!contents) - return false; - - content::RenderViewHost* render_view_host = contents->GetRenderViewHost(); - if (!render_view_host) - return false; - content::RenderWidgetHostView* view = render_view_host->GetView(); - if (!view) - return false; - - // Create a copy of this BackingStore image. - // This code is just copied from "thumbnail_generator.cc". - skia::PlatformCanvas canvas; - bool result = false; - bool done = false; - render_view_host->AsyncCopyFromBackingStore( - gfx::Rect(), - view->GetViewBounds().size(), - &canvas, - base::Bind(&CopyFromBackingStoreComplete, - &result, - &done)); - // RenderWidgetHost::AyncCopyFromBackingStore is currently implemented to run - // synchronously. - // TODO(mazda): Fix this so that it does not need to be synchronous - // (http://crbug.com/126203). - DCHECK(done); - if (!result) - return false; - - const SkBitmap& bitmap = skia::GetTopDevice(canvas)->accessBitmap(false); - bitmap.copyTo(preview, SkBitmap::kARGB_8888_Config); - return true; -} |