Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: chrome/browser/ui/views/select_file_dialog_win.cc

Issue 9203001: Implement input type=color UI (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: rebased Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/views/color_chooser_win.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/ui/select_file_dialog.h" 5 #include "chrome/browser/ui/select_file_dialog.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 "base/bind.h" 14 #include "base/bind.h"
15 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/i18n/case_conversion.h" 17 #include "base/i18n/case_conversion.h"
18 #include "base/message_loop.h" 18 #include "base/message_loop.h"
19 #include "base/string_split.h" 19 #include "base/string_split.h"
20 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/registry.h" 22 #include "base/win/registry.h"
23 #include "base/win/scoped_comptr.h" 23 #include "base/win/scoped_comptr.h"
24 #include "base/win/windows_version.h" 24 #include "base/win/windows_version.h"
25 #include "chrome/browser/ui/views/base_shell_dialog_win.h"
25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
26 #include "grit/generated_resources.h" 27 #include "grit/generated_resources.h"
27 #include "grit/ui_strings.h" 28 #include "grit/ui_strings.h"
28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
29 30
30 using content::BrowserThread; 31 using content::BrowserThread;
31 32
32 namespace { 33 namespace {
33 34
34 // Given |extension|, if it's not empty, then remove the leading dot. 35 // Given |extension|, if it's not empty, then remove the leading dot.
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 suggested_name, 383 suggested_name,
383 filter, 384 filter,
384 L"", 385 L"",
385 false, 386 false,
386 &index, 387 &index,
387 final_name); 388 final_name);
388 } 389 }
389 390
390 } // namespace 391 } // namespace
391 392
392 // Helpers to show certain types of Windows shell dialogs in a way that doesn't
393 // block the UI of the entire app.
394
395 class ShellDialogThread : public base::Thread {
396 public:
397 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
398 ~ShellDialogThread() {
399 Stop();
400 }
401
402 protected:
403 void Init() {
404 // Initializes the COM library on the current thread.
405 CoInitialize(NULL);
406 }
407
408 void CleanUp() {
409 // Closes the COM library on the current thread. CoInitialize must
410 // be balanced by a corresponding call to CoUninitialize.
411 CoUninitialize();
412 }
413
414 private:
415 DISALLOW_COPY_AND_ASSIGN(ShellDialogThread);
416 };
417
418 ///////////////////////////////////////////////////////////////////////////////
419 // A base class for all shell dialog implementations that handles showing a
420 // shell dialog modally on its own thread.
421 class BaseShellDialogImpl {
422 public:
423 BaseShellDialogImpl();
424 virtual ~BaseShellDialogImpl();
425
426 protected:
427 // Represents a run of a dialog.
428 struct RunState {
429 // Owning HWND, may be null.
430 HWND owner;
431
432 // Thread dialog is run on.
433 base::Thread* dialog_thread;
434 };
435
436 // Called at the beginning of a modal dialog run. Disables the owner window
437 // and tracks it. Returns the message loop of the thread that the dialog will
438 // be run on.
439 RunState BeginRun(HWND owner);
440
441 // Cleans up after a dialog run. If the run_state has a valid HWND this makes
442 // sure that the window is enabled. This is essential because BeginRun
443 // aggressively guards against multiple modal dialogs per HWND. Must be called
444 // on the UI thread after the result of the dialog has been determined.
445 //
446 // In addition this deletes the Thread in RunState.
447 void EndRun(RunState run_state);
448
449 // Returns true if a modal shell dialog is currently active for the specified
450 // owner. Must be called on the UI thread.
451 bool IsRunningDialogForOwner(HWND owner) const;
452
453 // Disables the window |owner|. Can be run from either the ui or the dialog
454 // thread. Can be called on either the UI or the dialog thread. This function
455 // is called on the dialog thread after the modal Windows Common dialog
456 // functions return because Windows automatically re-enables the owning
457 // window when those functions return, but we don't actually want them to be
458 // re-enabled until the response of the dialog propagates back to the UI
459 // thread, so we disable the owner manually after the Common dialog function
460 // returns.
461 void DisableOwner(HWND owner);
462
463 private:
464 // Creates a thread to run a shell dialog on. Each dialog requires its own
465 // thread otherwise in some situations where a singleton owns a single
466 // instance of this object we can have a situation where a modal dialog in
467 // one window blocks the appearance of a modal dialog in another.
468 static base::Thread* CreateDialogThread();
469
470 // Enables the window |owner_|. Can only be run from the ui thread.
471 void EnableOwner(HWND owner);
472
473 // A list of windows that currently own active shell dialogs for this
474 // instance. For example, if the DownloadManager owns an instance of this
475 // object and there are two browser windows open both with Save As dialog
476 // boxes active, this list will consist of the two browser windows' HWNDs.
477 // The derived class must call EndRun once the dialog is done showing to
478 // remove the owning HWND from this list.
479 // This object is static since it is maintained for all instances of this
480 // object - i.e. you can't have two file pickers open for the
481 // same owner, even though they might be represented by different instances
482 // of this object.
483 // This set only contains non-null HWNDs. NULL hwnds are not added to this
484 // list.
485 typedef std::set<HWND> Owners;
486 static Owners owners_;
487 static int instance_count_;
488
489 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
490 };
491
492 // static
493 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
494 int BaseShellDialogImpl::instance_count_ = 0;
495
496 BaseShellDialogImpl::BaseShellDialogImpl() {
497 ++instance_count_;
498 }
499
500 BaseShellDialogImpl::~BaseShellDialogImpl() {
501 // All runs should be complete by the time this is called!
502 if (--instance_count_ == 0)
503 DCHECK(owners_.empty());
504 }
505
506 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
507 // Cannot run a modal shell dialog if one is already running for this owner.
508 DCHECK(!IsRunningDialogForOwner(owner));
509 // The owner must be a top level window, otherwise we could end up with two
510 // entries in our map for the same top level window.
511 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
512 RunState run_state;
513 run_state.dialog_thread = CreateDialogThread();
514 run_state.owner = owner;
515 if (owner) {
516 owners_.insert(owner);
517 DisableOwner(owner);
518 }
519 return run_state;
520 }
521
522 void BaseShellDialogImpl::EndRun(RunState run_state) {
523 if (run_state.owner) {
524 DCHECK(IsRunningDialogForOwner(run_state.owner));
525 EnableOwner(run_state.owner);
526 DCHECK(owners_.find(run_state.owner) != owners_.end());
527 owners_.erase(run_state.owner);
528 }
529 DCHECK(run_state.dialog_thread);
530 delete run_state.dialog_thread;
531 }
532
533 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
534 return (owner && owners_.find(owner) != owners_.end());
535 }
536
537 void BaseShellDialogImpl::DisableOwner(HWND owner) {
538 if (IsWindow(owner))
539 EnableWindow(owner, FALSE);
540 }
541
542 // static
543 base::Thread* BaseShellDialogImpl::CreateDialogThread() {
544 base::Thread* thread = new ShellDialogThread;
545 bool started = thread->Start();
546 DCHECK(started);
547 return thread;
548 }
549
550 void BaseShellDialogImpl::EnableOwner(HWND owner) {
551 if (IsWindow(owner))
552 EnableWindow(owner, TRUE);
553 }
554
555 // Implementation of SelectFileDialog that shows a Windows common dialog for 393 // Implementation of SelectFileDialog that shows a Windows common dialog for
556 // choosing a file or folder. 394 // choosing a file or folder.
557 class SelectFileDialogImpl : public SelectFileDialog, 395 class SelectFileDialogImpl : public SelectFileDialog,
558 public BaseShellDialogImpl { 396 public BaseShellDialogImpl {
559 public: 397 public:
560 explicit SelectFileDialogImpl(Listener* listener); 398 explicit SelectFileDialogImpl(Listener* listener);
561 399
562 // BaseShellDialog implementation: 400 // BaseShellDialog implementation:
563 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE; 401 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE;
564 virtual void ListenerDestroyed() OVERRIDE; 402 virtual void ListenerDestroyed() OVERRIDE;
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
968 } 806 }
969 } 807 }
970 } 808 }
971 return success; 809 return success;
972 } 810 }
973 811
974 // static 812 // static
975 SelectFileDialog* SelectFileDialog::Create(Listener* listener) { 813 SelectFileDialog* SelectFileDialog::Create(Listener* listener) {
976 return new SelectFileDialogImpl(listener); 814 return new SelectFileDialogImpl(listener);
977 } 815 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/color_chooser_win.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698