Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 // Implementation of the manager for infobar windows. | |
| 6 | |
| 7 #include "chrome_frame/infobar_manager.h" | |
| 8 | |
| 9 #include <atlbase.h> | |
| 10 #include <atlapp.h> // Must be included AFTER base. | |
| 11 #include <atlcrack.h> | |
| 12 #include <atlmisc.h> | |
| 13 #include <atlwin.h> | |
| 14 | |
| 15 #include "base/logging.h" | |
| 16 #include "base/task_queue.h" | |
| 17 //#include "ceee/common/windows_constants.h" | |
| 18 #include "chrome_frame/utils.h" | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 const wchar_t kIeTabContentParentWindowClass[] = L"Shell DocObject View"; | |
| 23 | |
| 24 } // namespace | |
| 25 | |
| 26 DISABLE_RUNNABLE_METHOD_REFCOUNT(InfobarManager); | |
| 27 DISABLE_RUNNABLE_METHOD_REFCOUNT(InfobarManager::DisplacedWindowManager); | |
| 28 | |
| 29 | |
| 30 InfobarManager::InfobarHostImpl::InfobarHostImpl(InfobarManager *manager) | |
| 31 : manager_(manager) { | |
| 32 } | |
| 33 | |
| 34 HWND InfobarManager::InfobarHostImpl::GetContainerWindow() { | |
| 35 return manager_->container_window_; | |
| 36 } | |
| 37 | |
| 38 void InfobarManager::InfobarHostImpl::UpdateLayout() { | |
| 39 manager_->UpdateLayout(); | |
| 40 } | |
| 41 | |
| 42 // DisplacedWindowManager subclasses IE content window's container window, | |
| 43 // handles WM_NCCALCSIZE to resize its client area. It also handles WM_SIZE and | |
| 44 // WM_MOVE messages to make infobars consistent with IE content window's size | |
| 45 // and position. | |
| 46 // | |
| 47 // Finally, allows delayed tasks to be scheduled on the window's event loop. | |
| 48 class InfobarManager::DisplacedWindowManager | |
| 49 : public CWindowImpl<DisplacedWindowManager> { | |
| 50 public: | |
| 51 DisplacedWindowManager(InfobarManager* manager) | |
| 52 : infobar_manager_(manager) { | |
| 53 } | |
| 54 | |
| 55 // Returns true if the window is successfully subclassed, in which case this | |
| 56 // instance will take responsibility for its own destruction when the window | |
| 57 // is destroyed. If this method returns false, the caller should delete the | |
| 58 // instance immediately. | |
| 59 bool Initialize(HWND displaced_hwnd) { | |
| 60 PinModule(); | |
| 61 if (!SubclassWindow(displaced_hwnd)) { | |
| 62 LOG(DFATAL) << "Failed to subclass IE Renderer HWND for infobar " | |
| 63 << "installation."; | |
| 64 return false; | |
| 65 } | |
| 66 return true; | |
| 67 } | |
| 68 | |
| 69 virtual ~DisplacedWindowManager() { | |
| 70 if (IsWindow()) | |
| 71 UnsubclassWindow(); | |
| 72 } | |
| 73 | |
| 74 // Triggers a deferred re-evaluation of the dimensions of the displaced | |
| 75 // window. InfobarManager::AdjustDisplacedWindowDimensions will be called | |
| 76 // with the natural dimensions of the displaced window. | |
| 77 virtual void UpdateLayout() { | |
| 78 PushTask( | |
| 79 NewRunnableMethod(this, &DisplacedWindowManager::DoUpdateLayout)); | |
| 80 } | |
| 81 | |
| 82 // Schedules a deferred task on the window message loop of this instance's | |
| 83 // managed window. The task may not occur if the window is destroyed first. | |
| 84 virtual void PushTask(Task* task) { | |
| 85 task_queue_.Push(task); | |
| 86 if (IsWindow()) | |
| 87 PostMessage(TM_RUN_TASK_QUEUE, 0, 0); | |
| 88 } | |
| 89 | |
| 90 BEGIN_MSG_MAP_EX(DisplacedWindowManager) | |
| 91 MSG_WM_NCCALCSIZE(OnNcCalcSize) | |
| 92 MSG_WM_DESTROY(OnDestroy) | |
| 93 MESSAGE_HANDLER(TM_RUN_TASK_QUEUE, OnRunTaskQueue) | |
| 94 END_MSG_MAP() | |
| 95 | |
| 96 private: | |
| 97 enum DisplacedWindowUserMessages { | |
| 98 TM_RUN_TASK_QUEUE = WM_USER + 600, | |
| 99 }; | |
| 100 | |
| 101 LRESULT OnRunTaskQueue(UINT message, | |
| 102 WPARAM wparam, | |
| 103 LPARAM lparam, | |
| 104 BOOL& handled) { | |
| 105 task_queue_.Run(); | |
| 106 handled = TRUE; | |
| 107 return 0; | |
| 108 } | |
| 109 | |
| 110 void DoUpdateLayout() { | |
| 111 // Call SetWindowPos with SWP_FRAMECHANGED for IE window, then IE | |
| 112 // window would receive WM_NCCALCSIZE to recalculate its client size. | |
| 113 if (IsWindow()) | |
| 114 ::SetWindowPos(m_hWnd, | |
| 115 NULL, 0, 0, 0, 0, | |
| 116 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | | |
| 117 SWP_FRAMECHANGED); | |
| 118 } | |
| 119 | |
| 120 // Handles WM_NCCALCSIZE message. | |
| 121 LRESULT OnNcCalcSize(BOOL calc_valid_rects, LPARAM lparam) { | |
| 122 // Adjust client area for infobar. | |
| 123 LRESULT ret = DefWindowProc(WM_NCCALCSIZE, | |
| 124 static_cast<WPARAM>(calc_valid_rects), lparam); | |
| 125 // Whether calc_valid_rects is true or false, we could treat beginning of | |
| 126 // lparam as a RECT object. | |
| 127 RECT* rect = reinterpret_cast<RECT*>(lparam); | |
| 128 if (infobar_manager_ != NULL) | |
| 129 infobar_manager_->AdjustDisplacedWindowDimensions(rect); | |
| 130 | |
| 131 // If infobars reserve all the space and rect becomes empty, the container | |
| 132 // window won't receive subsequent WM_SIZE and WM_MOVE messages. | |
| 133 // In this case, we have to explicitly notify infobars to update their | |
| 134 // position. | |
| 135 //if (rect->right - rect->left <= 0 || rect->bottom - rect->top <= 0) | |
| 136 // PushTask( | |
| 137 // NewRunnableMethod(infobar_manager_, | |
| 138 // &InfobarManager::OnDisplacedWindowPositionChange)) ; | |
| 139 return ret; | |
| 140 } | |
| 141 | |
| 142 // The displaced window has been destroyed. Inform the InfobarManager, who | |
| 143 // will orphan this instance. We will delete ourselves in OnFinalMessage. | |
| 144 void OnDestroy() { | |
| 145 infobar_manager_->OnDisplacedWindowDestroyed(); | |
| 146 } | |
| 147 | |
| 148 void OnFinalMessage(HWND) { | |
| 149 delete this; | |
| 150 } | |
| 151 | |
| 152 InfobarManager* infobar_manager_; | |
| 153 TaskQueue task_queue_; | |
| 154 DISALLOW_COPY_AND_ASSIGN(DisplacedWindowManager); | |
| 155 }; | |
| 156 | |
| 157 InfobarManager::InfobarManager(HWND tab_window) | |
| 158 : container_window_(tab_window), | |
| 159 displaced_window_manager_(NULL), | |
| 160 infobar_host_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
| 161 for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { | |
|
amit
2010/11/12 00:04:49
Feels like an overkill for our rudimentary infobar
erikwright (departed)
2010/11/24 06:24:56
The TOP vs BOTTOM and sliding is unnecessary, but
| |
| 162 infobars_[index].reset( | |
| 163 new InfobarWindow(static_cast<InfobarType>(index), | |
| 164 &infobar_host_impl_)); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 HRESULT InfobarManager::Show(InfobarContent* content, | |
| 169 InfobarType type, | |
| 170 int max_height) { | |
| 171 if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || | |
|
grt (UTC plus 2)
2010/11/10 17:59:29
This looks like programmer error. Change to DCHEC
erikwright (departed)
2010/11/24 06:24:56
Yes. A relic of the original code. Ideally, I'd li
| |
| 172 infobars_[type] == NULL) { | |
|
grt (UTC plus 2)
2010/11/10 17:59:29
How about this one, programmer error or something
erikwright (departed)
2010/11/24 06:24:56
Yes. I'm updating it to only return success or fai
| |
| 173 return E_INVALIDARG; | |
| 174 } | |
| 175 | |
| 176 HRESULT hr = infobars_[type]->Show(content, max_height); | |
| 177 return hr; | |
| 178 } | |
| 179 | |
| 180 bool InfobarManager::UpdateLayout() { | |
| 181 if (FindDisplacedWindow()) { | |
| 182 displaced_window_manager_->UpdateLayout(); | |
| 183 return true; | |
| 184 } else { | |
| 185 return false; | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 HRESULT InfobarManager::Hide(InfobarType type) { | |
| 190 if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || | |
| 191 infobars_[type] == NULL) { | |
| 192 return E_INVALIDARG; | |
| 193 } | |
| 194 | |
| 195 infobars_[type]->Hide(); | |
| 196 return S_OK; | |
| 197 } | |
| 198 | |
| 199 void InfobarManager::HideAll() { | |
| 200 for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) | |
| 201 Hide(static_cast<InfobarType>(index)); | |
| 202 } | |
| 203 | |
| 204 // Callback function for EnumChildWindows. lParam should be the pointer to | |
| 205 // HWND variable where the handle of the window which class is | |
| 206 // kIeTabContentParentWindowClass will be written. | |
| 207 static BOOL CALLBACK FindDisplacedWindowProc(HWND hwnd, LPARAM lparam) { | |
| 208 HWND* window_handle = reinterpret_cast<HWND*>(lparam); | |
| 209 if (NULL == window_handle) { | |
|
grt (UTC plus 2)
2010/11/10 17:59:29
I prefer this style of comparison. For consistenc
erikwright (departed)
2010/11/24 06:24:56
Agreed. Not the least because scoped_ptr does not
| |
| 210 // It makes no sense to continue enumeration. | |
| 211 return FALSE; | |
| 212 } | |
| 213 | |
| 214 // Variable to hold the class name. The size does not matter as long as it | |
| 215 // is at least can hold kIeTabContentParentWindowClass. | |
| 216 wchar_t class_name[100]; | |
| 217 if (::GetClassName(hwnd, class_name, arraysize(class_name)) && | |
| 218 lstrcmpi(kIeTabContentParentWindowClass, class_name) == 0) { | |
| 219 // We found the window. Return its handle and stop enumeration. | |
| 220 *window_handle = hwnd; | |
| 221 return FALSE; | |
| 222 } | |
| 223 return TRUE; | |
| 224 } | |
| 225 | |
| 226 bool InfobarManager::FindDisplacedWindow() { | |
| 227 if (displaced_window_manager_ == NULL) { | |
| 228 if (::IsWindow(container_window_)) { | |
| 229 // Find the window which is the container for the HTML view (parent of | |
| 230 // the content). | |
| 231 HWND displaced_window = NULL; | |
| 232 ::EnumChildWindows(container_window_, FindDisplacedWindowProc, | |
| 233 reinterpret_cast<LPARAM>(&displaced_window)); | |
| 234 | |
| 235 if (displaced_window == NULL) { | |
| 236 LOG(DFATAL) << "Failed to locate IE renderer HWND to displace for " | |
| 237 << "Infobar installation."; | |
| 238 } else { | |
| 239 scoped_ptr<DisplacedWindowManager> displaced_window_manager( | |
| 240 new DisplacedWindowManager(this)); | |
| 241 if (displaced_window_manager->Initialize(displaced_window)) { | |
| 242 displaced_window_manager_ = displaced_window_manager.release(); | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 return displaced_window_manager_ != NULL; | |
| 249 } | |
| 250 | |
| 251 void InfobarManager::AdjustDisplacedWindowDimensions(RECT* rect) { | |
| 252 if (rect == NULL) | |
| 253 return; | |
| 254 | |
| 255 for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { | |
| 256 if (infobars_[index] != NULL) | |
| 257 infobars_[index]->ReserveSpace(rect); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 void InfobarManager::OnDisplacedWindowDestroyed() { | |
| 262 for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { | |
| 263 if (infobars_[index] != NULL) | |
| 264 infobars_[index]->Hide(); | |
| 265 } | |
| 266 // Will be deleted in its OnFinalMessage | |
| 267 displaced_window_manager_ = NULL; | |
| 268 } | |
| OLD | NEW |