Home | History | Annotate | Download | only in internal
      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