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