YSTest: Host.cpp 源文件

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
32 YSL_BEGIN
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
48 YSL_BEGIN_NAMESPACE(Host)
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)
267 YSLib::PostQuitMessage(0);
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