1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome_frame/infobars/internal/host_window_manager.h" 6 7 #include "chrome_frame/infobars/internal/displaced_window_manager.h" 8 9 namespace { 10 11 const wchar_t kIeTabContentParentWindowClass[] = L"Shell DocObject View"; 12 13 } // namespace 14 15 // Receives notification when the displaced window is destroyed, and forwards 16 // displaced window dimensions on to HostWindowManager::Delegate. 17 class HostWindowManager::DisplacedWindowDelegate 18 : public DisplacedWindowManager::Delegate { 19 public: 20 explicit DisplacedWindowDelegate(HostWindowManager* manager); 21 virtual ~DisplacedWindowDelegate(); 22 23 // DisplacedWindowManager::Delegate implementation 24 virtual void AdjustDisplacedWindowDimensions(RECT* rect); 25 26 private: 27 HostWindowManager* manager_; // Not owned by this instance 28 DISALLOW_COPY_AND_ASSIGN(DisplacedWindowDelegate); 29 }; // class HostWindowManager::DisplacedWindowDelegate 30 31 HostWindowManager::DisplacedWindowDelegate::DisplacedWindowDelegate( 32 HostWindowManager* manager) : manager_(manager) { 33 } 34 35 // Called when the displaced window is destroyed. Try to find a new displaced 36 // window. 37 HostWindowManager::DisplacedWindowDelegate::~DisplacedWindowDelegate() { 38 HWND old_window = *manager_->displaced_window_manager_; 39 // Will be deleted in its OnFinalMessage 40 manager_->displaced_window_manager_ = NULL; 41 42 // Check to see if a new window has already been created. 43 if (manager_->FindDisplacedWindow(old_window)) 44 manager_->UpdateLayout(); 45 } 46 47 // Forward this on to our delegate 48 void HostWindowManager::DisplacedWindowDelegate:: 49 AdjustDisplacedWindowDimensions(RECT* rect) { 50 manager_->delegate()->AdjustDisplacedWindowDimensions(rect); 51 } 52 53 // Callback function for EnumChildWindows (looks for a window with class 54 // kIeTabContentParentWindowClass). 55 // 56 // lparam must point to an HWND that is either NULL or the HWND of the displaced 57 // window that is being destroyed. We will ignore that window if we come across 58 // it, and update lparam to point to the new displaced window if it is found. 59 static BOOL CALLBACK FindDisplacedWindowProc(HWND hwnd, LPARAM lparam) { 60 DCHECK(lparam != NULL); 61 HWND* window_handle = reinterpret_cast<HWND*>(lparam); 62 63 if (hwnd == *window_handle) 64 return TRUE; // Skip this, it's the old displaced window. 65 66 // Variable to hold the class name. The size does not matter as long as it 67 // is at least can hold kIeTabContentParentWindowClass. 68 wchar_t class_name[100]; 69 if (::GetClassName(hwnd, class_name, arraysize(class_name)) && 70 lstrcmpi(kIeTabContentParentWindowClass, class_name) == 0) { 71 // We found the window. Return its handle and stop enumeration. 72 *window_handle = hwnd; 73 return FALSE; 74 } 75 return TRUE; 76 } 77 78 HostWindowManager::HostWindowManager() : displaced_window_manager_(NULL) { 79 } 80 81 HostWindowManager::~HostWindowManager() { 82 // If we are holding a displaced_window_manager_, it means that 83 // OnDisplacedWindowManagerDestroyed has not been called yet, and therefore 84 // our DisplacedWindowDelegate might still be around, ready to invoke us. 85 // Fail fast to prevent a call into lala-land. 86 CHECK(displaced_window_manager_ == NULL); 87 } 88 89 void HostWindowManager::UpdateLayout() { 90 if (FindDisplacedWindow(NULL)) 91 displaced_window_manager_->UpdateLayout(); 92 } 93 94 bool HostWindowManager::FindDisplacedWindow(HWND old_window) { 95 if (displaced_window_manager_ == NULL || 96 *displaced_window_manager_ == old_window) { 97 // Find the window which is the container for the HTML view (parent of 98 // the content). When the displaced window is destroyed, the new one might 99 // already exist, so we say "find a displaced window that is not this 100 // (old) one". 101 HWND displaced_window = old_window; 102 ::EnumChildWindows(*this, FindDisplacedWindowProc, 103 reinterpret_cast<LPARAM>(&displaced_window)); 104 105 if (displaced_window == old_window) { 106 LOG(ERROR) << "Failed to locate IE renderer HWND to displace for " 107 << "Infobar installation."; 108 } else { 109 scoped_ptr<DisplacedWindowManager> displaced_window_manager( 110 new DisplacedWindowManager()); 111 if (displaced_window_manager->Initialize( 112 displaced_window, new DisplacedWindowDelegate(this))) { 113 displaced_window_manager_ = displaced_window_manager.release(); 114 } 115 } 116 } 117 118 return displaced_window_manager_ != NULL; 119 } 120