neoWidgets
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
WindowModal.h
1 #ifndef NEO_WINDOWMODAL_H
2 #define NEO_WINDOWMODAL_H
3 
4 namespace neo
5 {
6 
13 class WindowModal : public Window
14 {
15 public:
17  WindowModal();
18 
24  int DoModal(bool blockEntireThread = true);
29  void EndModal(int result);
31  bool IsModal() { return modalLoopRunning; }
32 
34  static const int MODAL_ERROR = -1;
35 private:
37  virtual void ProcessMessage(MSG* msg);
38 
39  static BOOL CALLBACK CountEnabledWindows(HWND hwnd, LPARAM pBuffer);
40  static BOOL CALLBACK ListEnabledWindows(HWND hwnd, LPARAM pBuffer);
41 
42  // helper class if the entire thread should be blocked
43  class HwndBuffer
44  {
45  public:
46  HwndBuffer(HWND pMyWindow)
47  : myWindow(pMyWindow)
48  , filled(0)
49  {
50  count = 0;
51  hwnds = 0;
52  }
53  ~HwndBuffer()
54  {
55  delete [] hwnds;
56  }
57 
58  void EnableWindows(BOOL enable)
59  {
60  for(int i = 0; i < count; ++i)
61  EnableWindow(hwnds[i], enable);
62  }
63 
64  HWND myWindow; // handle of this instance, which should be excluded from enumeration
65  HWND* hwnds;
66  int filled; // counter for the enumeration
67  int count; // size of hwnds
68  };
69 
70  bool modalLoopRunning;
71  int modalResult;
72 };
73 
74 //-----------------------------------------------------------------------------
75 
77 {
78  modalLoopRunning = false;
79  modalResult = MODAL_ERROR;
80 }
81 
82 inline int WindowModal::DoModal(bool blockEntireThread)
83 {
84  // don't start modal loop on the same window twice
85  assert(!modalLoopRunning && GetHandle());
86  if(modalLoopRunning || GetHandle() == 0)
87  return MODAL_ERROR;
88 
89  HWND parent = reinterpret_cast<HWND>(GetWindowLongPtr(GetHandle(), GWLP_HWNDPARENT));
90 
91  // disable some windows
92  HwndBuffer windowsToDisable(GetHandle());
93  if(blockEntireThread)
94  {
95  // make a list of all windows we want to disable during modal message loop
96  EnumThreadWindows(GetCurrentThreadId(), CountEnabledWindows, (LPARAM)&windowsToDisable);
97  windowsToDisable.hwnds = new HWND[windowsToDisable.count];
98  EnumThreadWindows(GetCurrentThreadId(), ListEnabledWindows, (LPARAM)&windowsToDisable);
99  windowsToDisable.EnableWindows(FALSE);
100  }
101  else
102  EnableWindow(parent, FALSE);
103 
104  ShowWindow(GetHandle(), SW_SHOW);
105 
106  // modal message loop
107  modalLoopRunning = true;
108  while(modalLoopRunning)
109  {
110  MSG msg;
111  WaitMessage();
112  while(modalLoopRunning && PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
113  {
114  if(msg.message == WM_QUIT)
115  {
116  EndModal(-1);
117  PostQuitMessage((int)msg.wParam); // re-post
118  continue;
119  }
120  // virtual
121  ProcessMessage(&msg);
122  }
123  }
124 
125  // restore everything
126  if(blockEntireThread)
127  windowsToDisable.EnableWindows(TRUE);
128  else
129  EnableWindow(parent, TRUE);
130  // we need this if multiple modal loops are active (creating WindowModal inside another WindowModal)
131  BringWindowToTop(parent);
132  // hide after the parent is restored, otherwise the Z-Order goes wild
133  ShowWindow(GetHandle(), SW_HIDE);
134 
135  return modalResult;
136 }
137 
138 inline void WindowModal::EndModal(int result)
139 {
140  modalLoopRunning = false;
141  modalResult = result;
142 }
143 
144 inline void WindowModal::ProcessMessage(MSG* msg)
145 {
146  // behave like a dialog
147  if(!IsDialogMessage(GetHandle(), msg))
148  {
149  TranslateMessage(msg);
150  DispatchMessage(msg);
151  }
152 }
153 
154 inline BOOL CALLBACK WindowModal::CountEnabledWindows(HWND hwnd, LPARAM pBuffer)
155 {
156  HwndBuffer* buffer = (HwndBuffer*)pBuffer;
157  if(buffer && buffer->myWindow != hwnd && (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) == 0 && IsWindowEnabled(hwnd))
158  ++buffer->count;
159  return TRUE;
160 }
161 
162 inline BOOL CALLBACK WindowModal::ListEnabledWindows(HWND hwnd, LPARAM pBuffer)
163 {
164  HwndBuffer* buffer = (HwndBuffer*)pBuffer;
165  if(buffer && buffer->myWindow != hwnd && (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) == 0 && IsWindowEnabled(hwnd))
166  buffer->hwnds[buffer->filled++] = hwnd;
167  return TRUE;
168 }
169 
170 } // namespace neo
171 
172 #endif
bool IsModal()
Definition: WindowModal.h:31
General purpose window.
Definition: Window.h:12
This window can enter a modal message loop.
Definition: WindowModal.h:13
static const int MODAL_ERROR
Definition: WindowModal.h:34
void EndModal(int result)
Definition: WindowModal.h:138
WindowModal()
Definition: WindowModal.h:76
int DoModal(bool blockEntireThread=true)
Definition: WindowModal.h:82