1// Copyright (c) 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#ifndef UI_SHELL_DIALOGS_BASE_SHELL_DIALOG_WIN_H_
6#define UI_SHELL_DIALOGS_BASE_SHELL_DIALOG_WIN_H_
7
8#include <shlobj.h>
9#include <set>
10
11#include "ui/shell_dialogs/base_shell_dialog.h"
12#include "ui/shell_dialogs/shell_dialogs_export.h"
13
14namespace base {
15class Thread;
16}
17
18namespace ui {
19
20///////////////////////////////////////////////////////////////////////////////
21// A base class for all shell dialog implementations that handles showing a
22// shell dialog modally on its own thread.
23class SHELL_DIALOGS_EXPORT BaseShellDialogImpl {
24 public:
25  BaseShellDialogImpl();
26  virtual ~BaseShellDialogImpl();
27
28 protected:
29  // Represents a run of a dialog.
30  struct RunState {
31    // Owning HWND, may be null.
32    HWND owner;
33
34    // Thread dialog is run on.
35    base::Thread* dialog_thread;
36  };
37
38  // Called at the beginning of a modal dialog run. Disables the owner window
39  // and tracks it. Returns the message loop of the thread that the dialog will
40  // be run on.
41  RunState BeginRun(HWND owner);
42
43  // Cleans up after a dialog run. If the run_state has a valid HWND this makes
44  // sure that the window is enabled. This is essential because BeginRun
45  // aggressively guards against multiple modal dialogs per HWND. Must be called
46  // on the UI thread after the result of the dialog has been determined.
47  //
48  // In addition this deletes the Thread in RunState.
49  void EndRun(RunState run_state);
50
51  // Returns true if a modal shell dialog is currently active for the specified
52  // owner. Must be called on the UI thread.
53  bool IsRunningDialogForOwner(HWND owner) const;
54
55  // Disables the window |owner|. Can be run from either the ui or the dialog
56  // thread. Can be called on either the UI or the dialog thread. This function
57  // is called on the dialog thread after the modal Windows Common dialog
58  // functions return because Windows automatically re-enables the owning
59  // window when those functions return, but we don't actually want them to be
60  // re-enabled until the response of the dialog propagates back to the UI
61  // thread, so we disable the owner manually after the Common dialog function
62  // returns.
63  void DisableOwner(HWND owner);
64
65 private:
66  typedef std::set<HWND> Owners;
67
68  // Creates a thread to run a shell dialog on. Each dialog requires its own
69  // thread otherwise in some situations where a singleton owns a single
70  // instance of this object we can have a situation where a modal dialog in
71  // one window blocks the appearance of a modal dialog in another.
72  static base::Thread* CreateDialogThread();
73
74  // Enables the window |owner_|. Can only be run from the ui thread.
75  void EnableOwner(HWND owner);
76
77  // A list of windows that currently own active shell dialogs for this
78  // instance. For example, if the DownloadManager owns an instance of this
79  // object and there are two browser windows open both with Save As dialog
80  // boxes active, this list will consist of the two browser windows' HWNDs.
81  // The derived class must call EndRun once the dialog is done showing to
82  // remove the owning HWND from this list.
83  // This object is static since it is maintained for all instances of this
84  // object - i.e. you can't have two file pickers open for the
85  // same owner, even though they might be represented by different instances
86  // of this object.
87  // This set only contains non-null HWNDs. NULL hwnds are not added to this
88  // list.
89  static Owners owners_;
90  static int instance_count_;
91
92  DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
93};
94
95}  // namespace ui
96
97#endif  // UI_SHELL_DIALOGS_BASE_SHELL_DIALOG_WIN_H_
98
99