| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/shell_dialogs.h" | 5 #include "chrome/browser/shell_dialogs.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <commdlg.h> | 8 #include <commdlg.h> |
| 9 #include <shlobj.h> | 9 #include <shlobj.h> |
| 10 | 10 |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <set> | 12 #include <set> |
| 13 | 13 |
| 14 #include "app/gfx/font.h" | 14 #include "app/gfx/font.h" |
| 15 #include "app/l10n_util.h" | 15 #include "app/l10n_util.h" |
| 16 #include "app/win_util.h" | 16 #include "app/win_util.h" |
| 17 #include "base/file_util.h" | 17 #include "base/file_util.h" |
| 18 #include "base/registry.h" | 18 #include "base/registry.h" |
| 19 #include "base/scoped_comptr_win.h" | 19 #include "base/scoped_comptr_win.h" |
| 20 #include "base/string_util.h" | 20 #include "base/string_util.h" |
| 21 #include "base/thread.h" | 21 #include "base/thread.h" |
| 22 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/chrome_thread.h" |
| 23 #include "grit/generated_resources.h" | 23 #include "grit/generated_resources.h" |
| 24 | 24 |
| 25 // Helpers to show certain types of Windows shell dialogs in a way that doesn't | 25 // Helpers to show certain types of Windows shell dialogs in a way that doesn't |
| 26 // block the UI of the entire app. | 26 // block the UI of the entire app. |
| 27 | 27 |
| 28 class ShellDialogThread : public base::Thread { | 28 class ShellDialogThread : public base::Thread { |
| 29 public: | 29 public: |
| 30 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { } | 30 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { } |
| 31 | 31 |
| 32 protected: | 32 protected: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 // Disables the window |owner|. Can be run from either the ui or the dialog | 83 // Disables the window |owner|. Can be run from either the ui or the dialog |
| 84 // thread. Can be called on either the UI or the dialog thread. This function | 84 // thread. Can be called on either the UI or the dialog thread. This function |
| 85 // is called on the dialog thread after the modal Windows Common dialog | 85 // is called on the dialog thread after the modal Windows Common dialog |
| 86 // functions return because Windows automatically re-enables the owning | 86 // functions return because Windows automatically re-enables the owning |
| 87 // window when those functions return, but we don't actually want them to be | 87 // window when those functions return, but we don't actually want them to be |
| 88 // re-enabled until the response of the dialog propagates back to the UI | 88 // re-enabled until the response of the dialog propagates back to the UI |
| 89 // thread, so we disable the owner manually after the Common dialog function | 89 // thread, so we disable the owner manually after the Common dialog function |
| 90 // returns. | 90 // returns. |
| 91 void DisableOwner(HWND owner); | 91 void DisableOwner(HWND owner); |
| 92 | 92 |
| 93 // The UI thread's message loop. | |
| 94 MessageLoop* ui_loop_; | |
| 95 | |
| 96 private: | 93 private: |
| 97 // Creates a thread to run a shell dialog on. Each dialog requires its own | 94 // Creates a thread to run a shell dialog on. Each dialog requires its own |
| 98 // thread otherwise in some situations where a singleton owns a single | 95 // thread otherwise in some situations where a singleton owns a single |
| 99 // instance of this object we can have a situation where a modal dialog in | 96 // instance of this object we can have a situation where a modal dialog in |
| 100 // one window blocks the appearance of a modal dialog in another. | 97 // one window blocks the appearance of a modal dialog in another. |
| 101 static base::Thread* CreateDialogThread(); | 98 static base::Thread* CreateDialogThread(); |
| 102 | 99 |
| 103 // Enables the window |owner_|. Can only be run from the ui thread. | 100 // Enables the window |owner_|. Can only be run from the ui thread. |
| 104 void EnableOwner(HWND owner); | 101 void EnableOwner(HWND owner); |
| 105 | 102 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 119 static Owners owners_; | 116 static Owners owners_; |
| 120 static int instance_count_; | 117 static int instance_count_; |
| 121 | 118 |
| 122 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl); | 119 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl); |
| 123 }; | 120 }; |
| 124 | 121 |
| 125 // static | 122 // static |
| 126 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; | 123 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; |
| 127 int BaseShellDialogImpl::instance_count_ = 0; | 124 int BaseShellDialogImpl::instance_count_ = 0; |
| 128 | 125 |
| 129 BaseShellDialogImpl::BaseShellDialogImpl() | 126 BaseShellDialogImpl::BaseShellDialogImpl() { |
| 130 : ui_loop_(MessageLoop::current()) { | |
| 131 ++instance_count_; | 127 ++instance_count_; |
| 132 } | 128 } |
| 133 | 129 |
| 134 BaseShellDialogImpl::~BaseShellDialogImpl() { | 130 BaseShellDialogImpl::~BaseShellDialogImpl() { |
| 135 // All runs should be complete by the time this is called! | 131 // All runs should be complete by the time this is called! |
| 136 if (--instance_count_ == 0) | 132 if (--instance_count_ == 0) |
| 137 DCHECK(owners_.empty()); | 133 DCHECK(owners_.empty()); |
| 138 } | 134 } |
| 139 | 135 |
| 140 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { | 136 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 path = FilePath::FromWStringHack(path_as_wstring); | 361 path = FilePath::FromWStringHack(path_as_wstring); |
| 366 } | 362 } |
| 367 DisableOwner(params.run_state.owner); | 363 DisableOwner(params.run_state.owner); |
| 368 } else if (params.type == SELECT_OPEN_FILE) { | 364 } else if (params.type == SELECT_OPEN_FILE) { |
| 369 success = RunOpenFileDialog(params.title, filter, | 365 success = RunOpenFileDialog(params.title, filter, |
| 370 params.run_state.owner, &path); | 366 params.run_state.owner, &path); |
| 371 } else if (params.type == SELECT_OPEN_MULTI_FILE) { | 367 } else if (params.type == SELECT_OPEN_MULTI_FILE) { |
| 372 std::vector<FilePath> paths; | 368 std::vector<FilePath> paths; |
| 373 if (RunOpenMultiFileDialog(params.title, filter, | 369 if (RunOpenMultiFileDialog(params.title, filter, |
| 374 params.run_state.owner, &paths)) { | 370 params.run_state.owner, &paths)) { |
| 375 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 371 ChromeThread::PostTask( |
| 376 &SelectFileDialogImpl::MultiFilesSelected, | 372 ChromeThread::UI, FROM_HERE, |
| 377 paths, params.params, params.run_state)); | 373 NewRunnableMethod( |
| 374 this, &SelectFileDialogImpl::MultiFilesSelected, paths, |
| 375 params.params, params.run_state)); |
| 378 return; | 376 return; |
| 379 } | 377 } |
| 380 } | 378 } |
| 381 | 379 |
| 382 if (success) { | 380 if (success) { |
| 383 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 381 ChromeThread::PostTask( |
| 384 &SelectFileDialogImpl::FileSelected, path, filter_index, | 382 ChromeThread::UI, FROM_HERE, |
| 385 params.params, params.run_state)); | 383 NewRunnableMethod( |
| 384 this, &SelectFileDialogImpl::FileSelected, path, filter_index, |
| 385 params.params, params.run_state)); |
| 386 } else { | 386 } else { |
| 387 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 387 ChromeThread::PostTask( |
| 388 &SelectFileDialogImpl::FileNotSelected, params.params, | 388 ChromeThread::UI, FROM_HERE, |
| 389 params.run_state)); | 389 NewRunnableMethod( |
| 390 this, &SelectFileDialogImpl::FileNotSelected, params.params, |
| 391 params.run_state)); |
| 390 } | 392 } |
| 391 } | 393 } |
| 392 | 394 |
| 393 void SelectFileDialogImpl::FileSelected(const FilePath& selected_folder, | 395 void SelectFileDialogImpl::FileSelected(const FilePath& selected_folder, |
| 394 int index, | 396 int index, |
| 395 void* params, | 397 void* params, |
| 396 RunState run_state) { | 398 RunState run_state) { |
| 397 if (listener_) | 399 if (listener_) |
| 398 listener_->FileSelected(selected_folder, index, params); | 400 listener_->FileSelected(selected_folder, index, params); |
| 399 EndRun(run_state); | 401 EndRun(run_state); |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 void SelectFontDialogImpl::ExecuteSelectFont(RunState run_state, void* params) { | 652 void SelectFontDialogImpl::ExecuteSelectFont(RunState run_state, void* params) { |
| 651 LOGFONT logfont; | 653 LOGFONT logfont; |
| 652 CHOOSEFONT cf; | 654 CHOOSEFONT cf; |
| 653 cf.lStructSize = sizeof(cf); | 655 cf.lStructSize = sizeof(cf); |
| 654 cf.hwndOwner = run_state.owner; | 656 cf.hwndOwner = run_state.owner; |
| 655 cf.lpLogFont = &logfont; | 657 cf.lpLogFont = &logfont; |
| 656 cf.Flags = CF_SCREENFONTS; | 658 cf.Flags = CF_SCREENFONTS; |
| 657 bool success = !!ChooseFont(&cf); | 659 bool success = !!ChooseFont(&cf); |
| 658 DisableOwner(run_state.owner); | 660 DisableOwner(run_state.owner); |
| 659 if (success) { | 661 if (success) { |
| 660 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 662 ChromeThread::PostTask( |
| 661 &SelectFontDialogImpl::FontSelected, logfont, params, run_state)); | 663 ChromeThread::UI, FROM_HERE, |
| 664 NewRunnableMethod( |
| 665 this, &SelectFontDialogImpl::FontSelected, logfont, params, |
| 666 run_state)); |
| 662 } else { | 667 } else { |
| 663 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 668 ChromeThread::PostTask( |
| 664 &SelectFontDialogImpl::FontNotSelected, params, run_state)); | 669 ChromeThread::UI, FROM_HERE, |
| 670 NewRunnableMethod( |
| 671 this, &SelectFontDialogImpl::FontNotSelected, params, run_state)); |
| 665 } | 672 } |
| 666 } | 673 } |
| 667 | 674 |
| 668 void SelectFontDialogImpl::ExecuteSelectFontWithNameSize( | 675 void SelectFontDialogImpl::ExecuteSelectFontWithNameSize( |
| 669 RunState run_state, void* params, const std::wstring& font_name, | 676 RunState run_state, void* params, const std::wstring& font_name, |
| 670 int font_size) { | 677 int font_size) { |
| 671 // Create the HFONT from font name and size. | 678 // Create the HFONT from font name and size. |
| 672 HDC hdc = GetDC(NULL); | 679 HDC hdc = GetDC(NULL); |
| 673 long lf_height = -MulDiv(font_size, GetDeviceCaps(hdc, LOGPIXELSY), 72); | 680 long lf_height = -MulDiv(font_size, GetDeviceCaps(hdc, LOGPIXELSY), 72); |
| 674 ReleaseDC(NULL, hdc); | 681 ReleaseDC(NULL, hdc); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 CF_NOVERTFONTS | CF_SCRIPTSONLY | CF_LIMITSIZE; | 715 CF_NOVERTFONTS | CF_SCRIPTSONLY | CF_LIMITSIZE; |
| 709 | 716 |
| 710 // These limits are arbitrary and needs to be revisited. Is it bad | 717 // These limits are arbitrary and needs to be revisited. Is it bad |
| 711 // to clamp the size at 40 from A11Y point of view? | 718 // to clamp the size at 40 from A11Y point of view? |
| 712 cf.nSizeMin = 8; | 719 cf.nSizeMin = 8; |
| 713 cf.nSizeMax = 40; | 720 cf.nSizeMax = 40; |
| 714 | 721 |
| 715 bool success = !!ChooseFont(&cf); | 722 bool success = !!ChooseFont(&cf); |
| 716 DisableOwner(run_state.owner); | 723 DisableOwner(run_state.owner); |
| 717 if (success) { | 724 if (success) { |
| 718 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 725 ChromeThread::PostTask( |
| 719 &SelectFontDialogImpl::FontSelected, logfont, params, run_state)); | 726 ChromeThread::UI, FROM_HERE, |
| 727 NewRunnableMethod( |
| 728 this, &SelectFontDialogImpl::FontSelected, logfont, params, |
| 729 run_state)); |
| 720 } else { | 730 } else { |
| 721 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 731 ChromeThread::PostTask( |
| 722 &SelectFontDialogImpl::FontNotSelected, params, run_state)); | 732 ChromeThread::UI, FROM_HERE, |
| 733 NewRunnableMethod(this, &SelectFontDialogImpl::FontNotSelected, params, |
| 734 run_state)); |
| 723 } | 735 } |
| 724 } | 736 } |
| 725 | 737 |
| 726 void SelectFontDialogImpl::FontSelected(LOGFONT logfont, | 738 void SelectFontDialogImpl::FontSelected(LOGFONT logfont, |
| 727 void* params, | 739 void* params, |
| 728 RunState run_state) { | 740 RunState run_state) { |
| 729 if (listener_) { | 741 if (listener_) { |
| 730 HFONT font = CreateFontIndirect(&logfont); | 742 HFONT font = CreateFontIndirect(&logfont); |
| 731 if (font) { | 743 if (font) { |
| 732 listener_->FontSelected(gfx::Font::CreateFont(font), params); | 744 listener_->FontSelected(gfx::Font::CreateFont(font), params); |
| 733 DeleteObject(font); | 745 DeleteObject(font); |
| 734 } else { | 746 } else { |
| 735 listener_->FontSelectionCanceled(params); | 747 listener_->FontSelectionCanceled(params); |
| 736 } | 748 } |
| 737 } | 749 } |
| 738 EndRun(run_state); | 750 EndRun(run_state); |
| 739 } | 751 } |
| 740 | 752 |
| 741 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { | 753 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { |
| 742 if (listener_) | 754 if (listener_) |
| 743 listener_->FontSelectionCanceled(params); | 755 listener_->FontSelectionCanceled(params); |
| 744 EndRun(run_state); | 756 EndRun(run_state); |
| 745 } | 757 } |
| 746 | 758 |
| 747 // static | 759 // static |
| 748 SelectFontDialog* SelectFontDialog::Create(Listener* listener) { | 760 SelectFontDialog* SelectFontDialog::Create(Listener* listener) { |
| 749 return new SelectFontDialogImpl(listener); | 761 return new SelectFontDialogImpl(listener); |
| 750 } | 762 } |
| OLD | NEW |