YSTest  PreAlpha_b400_20130424
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
Host.cpp
浏览该文件的文档.
1 /*
2  Copyright by FrankHB 2013.
3 
4  This file is part of the YSLib project, and may only be used,
5  modified, and distributed under the terms of the YSLib project
6  license, LICENSE.TXT. By continuing to use, modify, or distribute
7  this file you indicate that you have read the license and
8  understand and accept it fully.
9 */
10 
28 #include "Host.h"
29 #include "Helper/GUIApplication.h"
30 #include "Helper/ShellHelper.h" // for YCL_DEBUG_PUTS, YSL_DEBUG_DECL_TIMER;
31 
33 
34 using namespace Drawing;
35 
36 namespace
37 {
38 
39 #if YCL_MINGW32 && 0
40 yconstexpr double g_max_free_fps(1000);
41 std::chrono::nanoseconds host_sleep(u64(1000000000 / g_max_free_fps));
42 #endif
43 
44 } // unnamed namespace;
45 
46 
47 #if YCL_HOSTED
49 
50 namespace
51 {
52 
53 # if YCL_MINGW32
54 ::LRESULT CALLBACK
55 WndProc(::HWND h_wnd, ::UINT msg, ::WPARAM w_param, ::LPARAM l_param)
56 {
57 // YSL_DEBUG_DECL_TIMER(tmr, "WndProc")
58  const auto p(reinterpret_cast<Window*>(::GetWindowLongPtrW(h_wnd,
59  GWLP_USERDATA)));
60 
61  switch(msg)
62  {
63  case WM_PAINT:
64  YCL_DEBUG_PUTS("Handling of WM_PAINT.");
65  if(p)
66  {
67  YSL_DEBUG_DECL_TIMER(tmr, "WM_PAINT")
68 
69  p->OnPaint();
70  }
71  break;
72  case WM_KILLFOCUS:
73  YCL_DEBUG_PUTS("Handling of WM_KILLFOCUS.");
74  if(p)
75  p->OnLostFocus();
76  break;
77  case WM_DESTROY:
78  YCL_DEBUG_PUTS("Handling of WM_DESTROY.");
79  if(p)
80  p->OnDestroy();
81  break;
82  default:
83  // YCL_DEBUG_PUTS("Handling of default procedure.");
84  return ::DefWindowProcW(h_wnd, msg, w_param, l_param);
85  }
86  return 0;
87 }
88 # endif
89 
90 } // unnamed namespace;
91 
92 
93 void
94 RenderWindow::OnPaint()
95 {
96  GSurface<WindowRegionDeviceContext> sf(GetNativeHandle());
97 
98  renderer.get().UpdateToSurface(sf);
99 }
100 
101 
102 WindowThread::~WindowThread()
103 {
104  YAssert(bool(p_wnd), "Null pointer found.");
105 
106  p_wnd->Close();
107  // NOTE: If the thread has been already completed there is no effect.
108  // TODO: Exception safety: add either assertion or logging when throwing
109  // other exceptions.
110  try
111  {
112  thrd.join();
113  }
114  catch(std::invalid_argument&)
115  {}
116 }
117 
118 void
119 WindowThread::ThreadLoop(NativeWindowHandle h_wnd)
120 {
121  p_wnd.reset(new Window(h_wnd));
122  WindowLoop(*p_wnd);
123 }
124 void
125 WindowThread::ThreadLoop(unique_ptr<Window> p)
126 {
127  p_wnd = std::move(p);
128  WindowLoop(*p_wnd);
129 }
130 
131 void
132 WindowThread::WindowLoop(Window& wnd)
133 {
134 # if YCL_MULTITHREAD
135  auto& env(wnd.GetHost());
136 
137  env.EnterWindowThread();
138 # endif
139  wnd.Show();
140  Environment::HostLoop();
141 # if YCL_MULTITHREAD
142  env.LeaveWindowThread();
143 # endif
144 }
145 
146 
147 void
148 HostRenderer::SetSize(const Size& s)
149 {
150  BufferedRenderer::SetSize(s);
151 }
152 
153 void
154 HostRenderer::Update(BitmapPtr buf)
155 {
156  YAssert(GetSizeOf(widget) == rbuf.GetSize(), "Mismatched size found.");
157 
158  rbuf.UpdateFrom(buf);
159  if(const auto p_wnd = GetWindowPtr())
160  rbuf.UpdateTo(p_wnd->GetNativeHandle());
161 }
162 
163 
164 Environment::Environment()
165  : wnd_map(), wmap_mtx()
166 # if YCL_MULTITHREAD == 1
167 # if YCL_MINGW32
168  , h_instance(::GetModuleHandleW(nullptr))
169 # endif
170  , wnd_thrd_count(), ExitOnAllWindowThreadCompleted()
171 # endif
172 {
173 # if YCL_MINGW32
174  const ::WNDCLASS wnd_class{CS_DBLCLKS/* | CS_HREDRAW | CS_VREDRAW*/,
175  WndProc, 0, 0, h_instance, ::LoadIconW(nullptr, IDI_APPLICATION),
176  ::LoadCursorW(nullptr, IDC_ARROW), ::HBRUSH(COLOR_MENU + 1),
177  nullptr, WindowClassName};
178 
179  if(!::RegisterClassW(&wnd_class))
180  throw LoggedEvent("Windows registration failed.");
181  // ::MessageBox(nullptr, "This program requires Windows NT!",
182  // wnd_title, MB_ICONERROR);
183  YCL_DEBUG_PUTS("Window class registered.");
184 # endif
185 }
186 Environment::~Environment()
187 {
188  YCL_DEBUG_PUTS("Host environment lifetime ended.");
189 
190  using ystdex::get_value;
191 
192  std::for_each(wnd_map.cbegin() | get_value, wnd_map.cend() | get_value,
193  [](Window* const& p){
194  p->Close();
195  });
196 # if YCL_MULTITHREAD == 1
197 # if YCL_MINGW32
198  ::UnregisterClassW(WindowClassName, h_instance);
199  YCL_DEBUG_PUTS("Window class unregistered.");
200 # endif
201 # endif
202 }
203 
204 Window*
205 Environment::GetForegroundWindow() const ynothrow
206 {
207 #ifdef YCL_MINGW32
208  return FindWindow(::GetForegroundWindow());
209 #endif
210  return nullptr;
211 }
212 
213 void
214 Environment::AddMappedItem(NativeWindowHandle h, Window* p)
215 {
216  std::unique_lock<std::mutex> lck(wmap_mtx);
217 
218  // TODO: Use %emplace.
219  wnd_map.insert(make_pair(h, p));
220 }
221 
222 Window*
223 Environment::FindWindow(NativeWindowHandle h) const ynothrow
224 {
225  std::unique_lock<std::mutex> lck(wmap_mtx);
226  const auto i(wnd_map.find(h));
227 
228  return i == wnd_map.end() ? nullptr : i->second;
229 }
230 
231 void
232 Environment::HostLoop()
233 {
234  YCL_DEBUG_PUTS("Host loop beginned.");
235 # if YCL_MINGW32
236  while(true)
237  {
238  ::MSG msg{nullptr, 0, 0, 0, 0, {0, 0}};
239 
240  if(::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE) != 0)
241  {
242  if(msg.message == WM_QUIT)
243  break;
244  // if(!PreTranslateMessage(&msg))
245  {
246  ::TranslateMessage(&msg);
247  ::DispatchMessageW(&msg);
248  }
249  // if(CheckCloseDialog(frm, false))
250  // break;
251  }
252  else
253  // std::this_thread::yield();
254  // std::this_thread::sleep_for(host_sleep);
255  // NOTE: Failure ignored.
256  ::WaitMessage();
257  }
258 # endif
259  YCL_DEBUG_PUTS("Host loop ended.");
260 }
261 
262 # if YCL_MULTITHREAD == 1
263 void
264 Environment::LeaveWindowThread()
265 {
266  if(--wnd_thrd_count == 0 && ExitOnAllWindowThreadCompleted)
268 }
269 # endif
270 
271 void
272 Environment::RemoveMappedItem(NativeWindowHandle h) ynothrow
273 {
274  std::unique_lock<std::mutex> lck(wmap_mtx);
275  const auto i(wnd_map.find(h));
276 
277  if(i != wnd_map.end())
278  wnd_map.erase(i);
279 }
280 
281 void
282 Environment::UpdateRenderWindows()
283 {
284  std::unique_lock<std::mutex> lck(wmap_mtx);
285 
286  for(const auto& pr : wnd_map)
287  if(auto p_wnd = dynamic_cast<RenderWindow*>(pr.second))
288  {
289  auto& rd(p_wnd->GetRenderer());
290  auto& wgt(rd.GetWidgetRef());
291 
292  if(rd.Validate(wgt, wgt,
293  {rd.GetContext(), Point(), GetBoundsOf(wgt)}))
294  rd.Update(rd.GetContext().GetBufferPtr());
295  }
296 }
297 
298 YSL_END_NAMESPACE(Host)
299 #endif
300 
301 YSL_END
302