15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/stdafx.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/chrome_app_view.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/metro_dialog_box.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/winrt_utils.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef winfoundtn::Collections::
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IVector<ABI::Windows::UI::Popups::IUICommand*> WindowsUICommands;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef winfoundtn::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand*>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AsyncCommandStatus;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MetroDialogBox::MetroDialogBox() {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button1_handler = NULL;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button2_handler = NULL;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MetroDialogBox::~MetroDialogBox() {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MetroDialogBox::Show(
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DialogBoxInfo& dialog_box_info) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only one dialog can be displayed at a given time.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dialog_box_.Get() == NULL);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The message dialog display does not work correctly in snapped mode.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winui::Popups::IMessageDialogFactory> message_dialog_factory;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = winrt_utils::CreateActivationFactory(
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RuntimeClass_Windows_UI_Popups_MessageDialog,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_dialog_factory.GetAddressOf());
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to activate IMessageDialogFactory");
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HString message_title;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_title.Attach(MakeHString(dialog_box_info.title));
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HString message_content;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_content.Attach(MakeHString(dialog_box_info.content));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = message_dialog_factory->CreateWithTitle(
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_content.Get(),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_title.Get(),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_box_.GetAddressOf());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to create message dialog");
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<WindowsUICommands> commands;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = dialog_box_->get_Commands(commands.GetAddressOf());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to create ui command collection");
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winui::Popups::IUICommandFactory> ui_command_factory;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = winrt_utils::CreateActivationFactory(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RuntimeClass_Windows_UI_Popups_UICommand,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui_command_factory.GetAddressOf());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to activate IUICommandFactory");
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HString label1;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label1.Attach(MakeHString(dialog_box_info.button1_label));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winui::Popups::IUICommand> label1_command;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = ui_command_factory->CreateWithHandler(
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      label1.Get(), this, label1_command.GetAddressOf());
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to add button1");
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HString label2;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label2.Attach(MakeHString(dialog_box_info.button2_label));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winui::Popups::IUICommand> label2_command;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = ui_command_factory->CreateWithHandler(label2.Get(), this,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             label2_command.GetAddressOf());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to add button2");
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands->Append(label1_command.Get());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands->Append(label2_command.Get());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<AsyncCommandStatus> ret;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = dialog_box_->ShowAsync(ret.GetAddressOf());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr, "Failed to show dialog");
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_ = dialog_box_info;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The dialog box displayed via the MessageDialog interface has the class name
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'Shell_Dialog'. The dialog box is top level window. To find it we enumerate
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all top level windows and compare the class names. If we find a matching
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// window class we compare its process id with ours and return the same.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL CALLBACK DialogBoxFinder(HWND hwnd, LPARAM lparam) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char classname[MAX_PATH] = {0};
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetClassNameA(hwnd, classname, ARRAYSIZE(classname))) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (lstrcmpiA("Shell_Dialog", classname) == 0) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "Found top most dialog box: " << classname;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "HWND: " << hwnd;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DWORD window_pid = 0;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DWORD window_tid = GetWindowThreadProcessId(hwnd, &window_pid);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "Window tid: " << window_tid;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "Window pid: " << window_pid;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (window_pid == ::GetCurrentProcessId()) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          HWND* dialog_window = reinterpret_cast<HWND*>(lparam);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *dialog_window = hwnd;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return FALSE;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MetroDialogBox::Dismiss() {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dialog_box_)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button1_handler = NULL;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button2_handler = NULL;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button1_label.clear();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_info_.button2_label.clear();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_box_.Reset();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't have a good way to dismiss the dialog box. Hack for now is to
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // find the dialog box class in our process and close it via the WM_CLOSE
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND dialog_box = NULL;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::EnumWindows(&DialogBoxFinder, reinterpret_cast<LPARAM>(&dialog_box));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::IsWindow(dialog_box))
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PostMessage(dialog_box, WM_CLOSE, 0, 0);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT STDMETHODCALLTYPE MetroDialogBox::Invoke(
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    winui::Popups::IUICommand* command) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HString label;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command->get_Label(label.GetAddressOf());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 button_label = MakeStdWString(label.Get());
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Clicked button label is : " << button_label;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (button_label == dialog_box_info_.button1_label) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Button1 clicked";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(dialog_box_info_.button1_handler);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dialog_box_info_.button1_handler();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (button_label == dialog_box_info_.button2_label) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Button2 clicked";
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(dialog_box_info_.button2_handler);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dialog_box_info_.button2_handler();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The dialog box is destroyed once we return from invoke. Go ahead and
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dismiss it.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dismiss();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
161