Index: chrome/browser/aeropeek_manager.cc |
diff --git a/chrome/browser/aeropeek_manager.cc b/chrome/browser/aeropeek_manager.cc |
deleted file mode 100644 |
index e00242a29f78b6a09c9674501abca455b68f7b1c..0000000000000000000000000000000000000000 |
--- 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; |
-} |