1 // Copyright (c) 2012 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 "win8/metro_driver/stdafx.h" 6 7 #include "win8/metro_driver/chrome_app_view.h" 8 #include "win8/metro_driver/metro_dialog_box.h" 9 #include "win8/metro_driver/winrt_utils.h" 10 11 typedef winfoundtn::Collections:: 12 IVector<ABI::Windows::UI::Popups::IUICommand*> WindowsUICommands; 13 14 typedef winfoundtn::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand*> 15 AsyncCommandStatus; 16 17 MetroDialogBox::MetroDialogBox() { 18 DVLOG(1) << __FUNCTION__; 19 dialog_box_info_.button1_handler = NULL; 20 dialog_box_info_.button2_handler = NULL; 21 } 22 23 MetroDialogBox::~MetroDialogBox() { 24 DVLOG(1) << __FUNCTION__; 25 } 26 27 void MetroDialogBox::Show( 28 const DialogBoxInfo& dialog_box_info) { 29 DVLOG(1) << __FUNCTION__; 30 31 // Only one dialog can be displayed at a given time. 32 DCHECK(dialog_box_.Get() == NULL); 33 34 // The message dialog display does not work correctly in snapped mode. 35 mswr::ComPtr<winui::Popups::IMessageDialogFactory> message_dialog_factory; 36 HRESULT hr = winrt_utils::CreateActivationFactory( 37 RuntimeClass_Windows_UI_Popups_MessageDialog, 38 message_dialog_factory.GetAddressOf()); 39 CheckHR(hr, "Failed to activate IMessageDialogFactory"); 40 41 mswrw::HString message_title; 42 message_title.Attach(MakeHString(dialog_box_info.title)); 43 44 mswrw::HString message_content; 45 message_content.Attach(MakeHString(dialog_box_info.content)); 46 47 hr = message_dialog_factory->CreateWithTitle( 48 message_content.Get(), 49 message_title.Get(), 50 dialog_box_.GetAddressOf()); 51 CheckHR(hr, "Failed to create message dialog"); 52 53 mswr::ComPtr<WindowsUICommands> commands; 54 hr = dialog_box_->get_Commands(commands.GetAddressOf()); 55 CheckHR(hr, "Failed to create ui command collection"); 56 57 mswr::ComPtr<winui::Popups::IUICommandFactory> ui_command_factory; 58 hr = winrt_utils::CreateActivationFactory( 59 RuntimeClass_Windows_UI_Popups_UICommand, 60 ui_command_factory.GetAddressOf()); 61 CheckHR(hr, "Failed to activate IUICommandFactory"); 62 63 mswrw::HString label1; 64 label1.Attach(MakeHString(dialog_box_info.button1_label)); 65 66 mswr::ComPtr<winui::Popups::IUICommand> label1_command; 67 hr = ui_command_factory->CreateWithHandler( 68 label1.Get(), this, label1_command.GetAddressOf()); 69 CheckHR(hr, "Failed to add button1"); 70 71 mswrw::HString label2; 72 label2.Attach(MakeHString(dialog_box_info.button2_label)); 73 74 mswr::ComPtr<winui::Popups::IUICommand> label2_command; 75 hr = ui_command_factory->CreateWithHandler(label2.Get(), this, 76 label2_command.GetAddressOf()); 77 CheckHR(hr, "Failed to add button2"); 78 79 commands->Append(label1_command.Get()); 80 commands->Append(label2_command.Get()); 81 82 mswr::ComPtr<AsyncCommandStatus> ret; 83 hr = dialog_box_->ShowAsync(ret.GetAddressOf()); 84 CheckHR(hr, "Failed to show dialog"); 85 86 dialog_box_info_ = dialog_box_info; 87 } 88 89 // The dialog box displayed via the MessageDialog interface has the class name 90 // 'Shell_Dialog'. The dialog box is top level window. To find it we enumerate 91 // all top level windows and compare the class names. If we find a matching 92 // window class we compare its process id with ours and return the same. 93 BOOL CALLBACK DialogBoxFinder(HWND hwnd, LPARAM lparam) { 94 char classname[MAX_PATH] = {0}; 95 96 if (::GetClassNameA(hwnd, classname, ARRAYSIZE(classname))) { 97 if (lstrcmpiA("Shell_Dialog", classname) == 0) { 98 if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) { 99 DVLOG(1) << "Found top most dialog box: " << classname; 100 DVLOG(1) << "HWND: " << hwnd; 101 DWORD window_pid = 0; 102 DWORD window_tid = GetWindowThreadProcessId(hwnd, &window_pid); 103 DVLOG(1) << "Window tid: " << window_tid; 104 DVLOG(1) << "Window pid: " << window_pid; 105 106 if (window_pid == ::GetCurrentProcessId()) { 107 HWND* dialog_window = reinterpret_cast<HWND*>(lparam); 108 *dialog_window = hwnd; 109 return FALSE; 110 } 111 } 112 } 113 } 114 return TRUE; 115 } 116 117 void MetroDialogBox::Dismiss() { 118 DVLOG(1) << __FUNCTION__; 119 if (!dialog_box_) 120 return; 121 122 dialog_box_info_.button1_handler = NULL; 123 dialog_box_info_.button2_handler = NULL; 124 dialog_box_info_.button1_label.clear(); 125 dialog_box_info_.button2_label.clear(); 126 dialog_box_.Reset(); 127 128 // We don't have a good way to dismiss the dialog box. Hack for now is to 129 // find the dialog box class in our process and close it via the WM_CLOSE 130 // message. 131 HWND dialog_box = NULL; 132 ::EnumWindows(&DialogBoxFinder, reinterpret_cast<LPARAM>(&dialog_box)); 133 if (::IsWindow(dialog_box)) 134 PostMessage(dialog_box, WM_CLOSE, 0, 0); 135 } 136 137 HRESULT STDMETHODCALLTYPE MetroDialogBox::Invoke( 138 winui::Popups::IUICommand* command) { 139 DVLOG(1) << __FUNCTION__; 140 141 mswrw::HString label; 142 command->get_Label(label.GetAddressOf()); 143 144 string16 button_label = MakeStdWString(label.Get()); 145 DVLOG(1) << "Clicked button label is : " << button_label; 146 if (button_label == dialog_box_info_.button1_label) { 147 DVLOG(1) << "Button1 clicked"; 148 DCHECK(dialog_box_info_.button1_handler); 149 dialog_box_info_.button1_handler(); 150 } else if (button_label == dialog_box_info_.button2_label) { 151 DVLOG(1) << "Button2 clicked"; 152 DCHECK(dialog_box_info_.button2_handler); 153 dialog_box_info_.button2_handler(); 154 } 155 // The dialog box is destroyed once we return from invoke. Go ahead and 156 // dismiss it. 157 Dismiss(); 158 return S_OK; 159 } 160 161