1 // Copyright 2013 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/turndown_prompt/turndown_prompt_window.h" 6 7 #include <atlctrls.h> 8 #include <commctrl.h> 9 #include <shellapi.h> 10 11 #include "base/compiler_specific.h" 12 #include "chrome_frame/ready_mode/internal/url_launcher.h" 13 #include "chrome_frame/simple_resource_loader.h" 14 #include "chrome_frame/utils.h" 15 #include "grit/chrome_frame_dialogs.h" 16 #include "grit/chrome_frame_resources.h" 17 #include "grit/chromium_strings.h" 18 19 // atlctrlx.h requires 'min' and 'max' macros, the definition of which conflicts 20 // with STL headers. Hence we include them out of the order defined by style 21 // guidelines. As a result you may not refer to std::min or std::max in this 22 // file. 23 #include <minmax.h> // NOLINT 24 #include <atlctrlx.h> // NOLINT 25 26 namespace { 27 const uint32 kBitmapImageSize = 18; 28 } // namespace 29 30 // WTL's CBitmapButton's drawing code is horribly broken when using transparent 31 // images (specifically, it doesn't clear the background between redraws). 32 // Fix it here. 33 class CFBitmapButton: public CBitmapButtonImpl<CFBitmapButton> 34 { 35 public: 36 DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName()) 37 38 CFBitmapButton() 39 : CBitmapButtonImpl<CFBitmapButton>(BMPBTN_AUTOSIZE | BMPBTN_HOVER, 40 NULL) {} 41 42 // "Overridden" from CBitmapButtonImpl via template hackery. See 43 // CBitmapButtonImpl::OnPaint() in atlctrlx.h for details. 44 void DoPaint(CDCHandle dc) { 45 RECT rc = {0}; 46 GetClientRect(&rc); 47 dc.FillRect(&rc, reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1)); 48 49 // Call original implementation. 50 CBitmapButtonImpl<CFBitmapButton>::DoPaint(dc); 51 } 52 }; 53 54 // static 55 base::WeakPtr<TurndownPromptWindow> TurndownPromptWindow::CreateInstance( 56 InfobarContent::Frame* frame, 57 UrlLauncher* url_launcher, 58 const base::Closure& uninstall_callback) { 59 DCHECK(frame != NULL); 60 DCHECK(url_launcher != NULL); 61 62 base::WeakPtr<TurndownPromptWindow> instance( 63 (new TurndownPromptWindow(frame, url_launcher, uninstall_callback)) 64 ->weak_ptr_factory_.GetWeakPtr()); 65 66 DCHECK(!instance->IsWindow()); 67 68 if (instance->Create(frame->GetFrameWindow()) == NULL) { 69 DPLOG(ERROR) << "Failed to create HWND for TurndownPromptWindow."; 70 return base::WeakPtr<TurndownPromptWindow>(); 71 } 72 73 // Subclass the "Learn more." text to make it behave like a link. Clicks are 74 // routed to OnLearnMore(). 75 CWindow rte = instance->GetDlgItem(IDC_TD_PROMPT_LINK); 76 instance->link_.reset(new CHyperLink()); 77 instance->link_->SubclassWindow(rte); 78 instance->link_->SetHyperLinkExtendedStyle(HLINK_NOTIFYBUTTON, 79 HLINK_NOTIFYBUTTON); 80 81 SetupBitmapButton(instance.get()); 82 83 // Substitute the proper text given the current IE version. 84 CWindow text = instance->GetDlgItem(IDC_TD_PROMPT_MESSAGE); 85 string16 prompt_text(GetPromptText()); 86 if (!prompt_text.empty()) 87 text.SetWindowText(prompt_text.c_str()); 88 89 return instance; 90 } 91 92 TurndownPromptWindow::TurndownPromptWindow( 93 InfobarContent::Frame* frame, 94 UrlLauncher* url_launcher, 95 const base::Closure& uninstall_closure) 96 : frame_(frame), 97 url_launcher_(url_launcher), 98 uninstall_closure_(uninstall_closure), 99 weak_ptr_factory_(this) { 100 } 101 102 TurndownPromptWindow::~TurndownPromptWindow() {} 103 104 // static 105 void TurndownPromptWindow::SetupBitmapButton(TurndownPromptWindow* instance) { 106 DCHECK(instance); 107 CWindow close_window = instance->GetDlgItem(IDDISMISS); 108 instance->close_button_.reset(new CFBitmapButton()); 109 110 // Set the resource instance to the current dll which contains the bitmap. 111 HINSTANCE old_res_module = _AtlBaseModule.GetResourceInstance(); 112 HINSTANCE this_module = _AtlBaseModule.GetModuleInstance(); 113 _AtlBaseModule.SetResourceInstance(this_module); 114 115 HBITMAP close_bitmap = static_cast<HBITMAP>( 116 LoadImage(this_module, MAKEINTRESOURCE(IDB_TURNDOWN_PROMPT_CLOSE_BUTTON), 117 IMAGE_BITMAP, 0, 0, 0)); 118 119 // Restore the module's resource instance. 120 _AtlBaseModule.SetResourceInstance(old_res_module); 121 122 // Create the image list with the appropriate size and colour mask. 123 instance->close_button_->m_ImageList.Create(kBitmapImageSize, 124 kBitmapImageSize, 125 ILC_COLOR8 | ILC_MASK, 4, 0); 126 instance->close_button_->m_ImageList.Add(close_bitmap, RGB(255, 0, 255)); 127 instance->close_button_->m_ImageList.SetBkColor(CLR_NONE); 128 129 // Free up the original bitmap. 130 DeleteObject(close_bitmap); 131 132 // Configure the button states and initialize the button. 133 instance->close_button_->SetImages(0, 1, 2, 3); 134 instance->close_button_->SubclassWindow(close_window); 135 136 // The CDialogResize() implementation incorrectly captures the size 137 // of the bitmap image button. Reset it here to ensure that resizing works 138 // as desired. 139 140 // Find the resize data. The parameters here must match the resize map in 141 // turndown_prompt_window.h. 142 _AtlDlgResizeData resize_params = { IDDISMISS, DLSZ_CENTER_Y | DLSZ_MOVE_X }; 143 int resize_index = instance->m_arrData.Find(resize_params); 144 DCHECK(resize_index > -1 && resize_index < instance->m_arrData.GetSize()); 145 146 // Fiddle CDialogResize's internal data to fix up the size for the image 147 // control. 148 _AtlDlgResizeData& resize_data = instance->m_arrData[resize_index]; 149 resize_data.m_rect.right = resize_data.m_rect.left + kBitmapImageSize; 150 resize_data.m_rect.top = 0; 151 resize_data.m_rect.bottom = kBitmapImageSize; 152 } 153 154 void TurndownPromptWindow::OnFinalMessage(HWND) { 155 delete this; 156 } 157 158 void TurndownPromptWindow::OnDestroy() { 159 close_button_->m_ImageList.Destroy(); 160 frame_ = NULL; 161 } 162 163 BOOL TurndownPromptWindow::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { 164 DlgResize_Init(false); // false => 'no gripper' 165 return TRUE; 166 } 167 168 LRESULT TurndownPromptWindow::OnLearnMore(WORD /*wParam*/, 169 LPNMHDR /*lParam*/, 170 BOOL& /*bHandled*/) { 171 url_launcher_->LaunchUrl(SimpleResourceLoader::Get( 172 IDS_CHROME_FRAME_TURNDOWN_LEARN_MORE_URL)); 173 return 0; 174 } 175 176 LRESULT TurndownPromptWindow::OnUninstall(WORD /*wNotifyCode*/, 177 WORD /*wID*/, 178 HWND /*hWndCtl*/, 179 BOOL& /*bHandled*/) { 180 frame_->CloseInfobar(); 181 if (!uninstall_closure_.is_null()) 182 uninstall_closure_.Run(); 183 return 0; 184 } 185 186 LRESULT TurndownPromptWindow::OnDismiss(WORD /*wNotifyCode*/, 187 WORD /*wID*/, 188 HWND /*hWndCtl*/, 189 BOOL& /*bHandled*/) { 190 frame_->CloseInfobar(); 191 return 0; 192 } 193 194 // static 195 string16 TurndownPromptWindow::GetPromptText() { 196 IEVersion ie_version = GetIEVersion(); 197 int message_id = IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_NEWER; 198 if (ie_version == IE_6 || ie_version == IE_7 || ie_version == IE_8) 199 message_id = IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_OLDER; 200 return SimpleResourceLoader::GetInstance()->Get(message_id); 201 } 202