YSTest: HostRenderer.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

HostRenderer.cpp
浏览该文件的文档.
1 /*
2 © 2013-2016 FrankHB.
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 "Helper/YModules.h"
29 #include YFM_Helper_HostRenderer // for ystdex::pvoid;
30 #include YFM_Helper_Environment
31 #include YFM_Helper_GUIApplication // for GUIHost;
32 #if YCL_HostedUI_XCB
33 # include <xcb/xcb.h>
34 # include YFM_YCLib_XCB
35 #elif YCL_Win32
36 # include YFM_Win32_Helper_Win32Control
37 #endif
38 #include <ystdex/scope_guard.hpp> // for ystdex::unique_guard;
39
40 namespace YSLib
41 {
42
43 using namespace Drawing;
44
45 #if YF_Hosted
46 namespace Host
47 {
48
49 RenderWindow::RenderWindow(HostRenderer& rd, NativeWindowHandle h)
50 : Window(h), renderer(rd)
51 {
52 # if YCL_HostedUI_XCB
53 MessageMap[XCB_EXPOSE] += [this]{
54 // TODO: Optimize using event parameter.
55 YSLib::Deref(renderer.get().GetBufferRef().Lock()).UpdateTo(
56 GetNativeHandle());
57 };
58 # elif YCL_Win32
59 yunseq(
60 MessageMap[WM_ERASEBKGND]
61 += [](::LPARAM, ::WPARAM, ::LRESULT& res) ynothrow{
62 res = 1;
63 },
64 MessageMap[WM_PAINT] += [this]{
65 // NOTE: Parameters are not used.
66 GSurface<WindowRegionDeviceContext> sf(GetNativeHandle());
67
68 renderer.get().UpdateBoundsToSurface(sf, sf.GetInvalidatedArea());
69 }
70 );
71 # endif
72 }
73
74 void
75 RenderWindow::Refresh()
76 {
77 GetRenderer().RefreshForWidget();
78 }
79
80
81 WindowThread::~WindowThread()
82 {
83 const unique_ptr<Window> p_hold(Nonnull(GetWindowPtr().get()));
84
85 YTraceDe(Debug, "Ready to close window '%p' on leaving window"
86 " thread.", ystdex::pvoid(p_hold.get()));
87
88 FilterExceptions([&, this]{
89 # if !YCL_Android
90 TryExpr(p_hold->Close())
91 // TODO: Log.
92 # if YCL_HostedUI_XCB
93 CatchIgnore(XCB::XCBException&)
94 # endif
95 # if YCL_Win32
96 CatchIgnore(Win32Exception&)
97 # else
98 CatchIgnore(Exception&) // TODO: Use proper platform-dependent type.
99 # endif
100 # endif
101 YTraceDe(Informative, "Ready to join the window thread '%p' of closed"
102 " window '%p'.", ystdex::pvoid(&thrd), ystdex::pvoid(p_hold.get()));
103 thrd.join();
104 YTraceDe(Debug, "Window thread '%p' joined.",
105 ystdex::pvoid(&thrd));
106 }, yfsig);
107 }
108
109 WindowThread::Guard
110 WindowThread::DefaultGenerateGuard(Window& wnd)
111 {
112 #if YF_Multithread == 1
113 wnd.GetGUIHostRef().EnterWindowThread();
114 return ystdex::unique_guard([&]() ynothrow{
115 FilterExceptions([&]{
116 wnd.GetGUIHostRef().LeaveWindowThread();
117 }, "default event guard destructor");
118 });
119 #else
120 return {};
121 #endif
122 }
123
124 void
125 WindowThread::ThreadLoop(NativeWindowHandle h_wnd)
126 {
127 ThreadLoop(make_unique<Window>(h_wnd));
128 }
129 void
130 WindowThread::ThreadLoop(unique_ptr<Window> p_wnd)
131 {
132 YAssert(!p_window, "Duplicate window initialization detected.");
133
134 auto& wnd(Deref(p_wnd));
135
136 p_window = p_wnd.release();
137 WindowLoop(wnd, GenerateGuard);
138 }
139
140 void
141 WindowThread::WindowLoop(Window& wnd)
142 {
143 YTraceDe(Informative, "Host loop began.");
144 # if YCL_HostedUI_XCB
145 // XXX: Exit on I/O error occurred?
146 // TODO: Log I/O error.
147 while(const auto p_evt = unique_raw(::xcb_wait_for_event(
148 &Deref(wnd.GetNativeHandle().get()).DerefConn()), std::free))
149 {
150 // YSL_DEBUG_DECL_TIMER(tmr, to_string(msg));
151 auto& m(wnd.MessageMap);
152 const auto msg(p_evt->response_type & ~0x80);
153
154 if(msg == XCB_CLIENT_MESSAGE)
155 {
156 auto& cevt(reinterpret_cast<::xcb_client_message_event_t&>(*p_evt));
157
158 if(cevt.type == wnd.WM_PROTOCOLS
159 && cevt.data.data32[0] == wnd.WM_DELETE_WINDOW)
160 break;
161 }
162
163 const auto i(m.find(msg & ~0x80));
164
165 if(i != m.cend())
166 i->second(p_evt.get());
167 }
168 # else
169 yunused(wnd);
170 # if YCL_Win32
171
172 ::MSG msg{nullptr, 0, 0, 0, 0, {0, 0}};
173 int res;
174
175 while((res = ::GetMessageW(&msg, nullptr, 0, 0)) != 0)
176 {
177
178 // XXX: Error ignored.
179 if(res != -1)
180 {
181 ::TranslateMessage(&msg);
182 ::DispatchMessageW(&msg);
183 }
184 else
185 YCL_Trace_Win32Error(Warning, GetMessageW, yfsig);
186 }
187 # endif
188 # endif
189 YTraceDe(Informative, "Host loop ended.");
190 }
191 void
192 WindowThread::WindowLoop(Window& wnd, GuardGenerator gd_gen)
193 {
194 const auto gd(gd_gen ? gd_gen(wnd) : Guard());
195
196 WindowLoop(wnd);
197 }
198
199
200 HostRenderer::~HostRenderer()
201 {
202 #if YCL_Win32
203 FilterExceptions([this]{
204 try
205 {
206 auto& wnd(Wait());
207
208 wnd.GetGUIHostRef().Desktop -= widget;
209 if(const auto p_wgt = dynamic_cast<UI::Widget*>(&widget.get()))
210 p_wgt->SetView({});
211 }
212 CatchIgnore(Windows::UI::ViewSignal&)
213 }, yfsig);
214 #endif
215 }
216
217 void
218 HostRenderer::SetSize(const Size& s)
219 {
220 BufferedRenderer::SetSize(s),
221 Deref(rbuf.Lock()).Resize(s);
222 }
223
224 bool
225 HostRenderer::AdjustSize()
226 {
227 const auto& view_size(GetSizeOf(widget));
228 const auto& buf_size(GetContext().GetSize());
229
230 if(YB_UNLIKELY(view_size != buf_size))
231 {
232 YTraceDe(Warning, "Mismatched host renderer buffer size %s found.",
233 to_string(buf_size).c_str());
234 SetSize(view_size);
235 YTraceDe(Warning, "Host renderer buffer size has adjusted to view size"
236 " %s.", to_string(view_size).c_str());
237 return true;
238 }
239 return {};
240 }
241
242 void
243 HostRenderer::InitWidgetView()
244 {
245 #if YCL_Win32
246 auto& wnd(Wait());
247
248 if(const auto p_wgt = dynamic_cast<UI::Widget*>(&widget.get()))
249 p_wgt->SetView(
250 make_unique<Windows::UI::ControlView>(wnd.GetNativeHandle()));
251 wnd.GetGUIHostRef().Desktop += widget;
252 #endif
253 // FIXME: Allow user to specify which kinds of views should be adjusted.
254 auto& view_ref(widget.get().GetView());
255
256 RootMode = typeid(view_ref) == typeid(UI::View);
257 }
258
259 void
260 HostRenderer::RefreshForWidget()
261 {
262 if(const auto p_wnd = GetWindowPtr())
263 {
264 #if YCL_Win32
265 if(!p_wnd->IsMinimized())
266 #else
267 yunused(p_wnd);
268 #endif
269 {
270 // TODO: Determine what should be painted for thumbnail.
271 // TODO: Provide interface for custom painting.
272 AdjustSize();
273
274 auto& wgt(GetWidgetRef());
275 const auto& g(GetContext());
276 const auto r(GetInvalidatedArea());
277
278 if(Validate(wgt, wgt, {g, {}, r}))
279 Update(g.GetBufferPtr(), r);
280 }
281 }
282 }
283
284 void
285 HostRenderer::Update(ConstBitmapPtr p, const Rect& r)
286 {
287 YAssertNonnull(p);
288 if(const auto p_wnd = GetWindowPtr())
289 try
290 {
291 auto& view(widget.get().GetView());
292 const auto& view_size(view.GetSize());
293 auto p_buf(rbuf.Lock());
294 auto& buf(Deref(p_buf));
295 const auto& buf_size(buf.GetSize());
296
297 if(YB_UNLIKELY(view_size != buf_size))
298 throw LoggedEvent(ystdex::sfmt("Mismatched host renderer buffer"
299 " size %s and view size %s found.",
300 to_string(buf_size).c_str(), to_string(view_size).c_str()));
301 if(RootMode)
302 {
303 # if YCL_HostedUI_XCB
304 const Rect& cbounds(p_wnd->GetBounds());
305 # elif YCL_Android
306 const Rect cbounds(p_wnd->GetSize());
307 # else
308 const Rect& cbounds(p_wnd->GetClientBounds());
309 # endif
310 auto bounds(cbounds);
311 const auto& loc(view.GetLocation());
312
313 if(!loc.IsZero())
314 {
315 bounds.GetPointRef() += loc;
316 view.SetLocation({});
317 rInvalidated = {{}, bounds.GetSize()};
318 Validate(widget, widget, {GetContext(), {}, rInvalidated});
319 }
320 bounds.GetSizeRef() = view_size;
321 # if !YCL_Android
322 if(bounds != cbounds)
323 # if YCL_HostedUI_XCB
324 p_wnd->SetBounds(bounds);
325 # else
326 p_wnd->SetClientBounds(bounds);
327 # endif
328 # endif
329 }
330 #if YCL_Win32
331 p_wnd->UpdateFromBounds(p, buf, r, r.GetPoint());
332 #else
333 yunused(r);
334 p_wnd->UpdateFrom(p, buf);
335 #endif
336 }
337 # if YCL_Win32
338 CatchIgnore(Win32Exception&)
339 # else
340 CatchIgnore(Exception&) // XXX: Use proper platform-dependent type.
341 # endif
342 }
343
344 Window&
345 HostRenderer::Wait()
346 {
347 observer_ptr<Host::Window> p_wnd;
348
349 // XXX: Busy wait.
350 while(!p_wnd)
351 p_wnd = GetWindowPtr();
352 return *p_wnd;
353 }
354
355 } // namespace Host;
356 #endif
357
358 } // namespace YSLib;
359
platform::p
while p p
Definition: YCLib/FileSystem.h:225
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1140
platform::Nonnull
_type && Nonnull(_type &&p) ynothrow
断言并返回非空指针。
Definition: Debug.h:411
platform::Descriptions::Warning
Definition: YCommon.h:157
platform::Descriptions::Informative
Definition: YCommon.h:159
YSLib::Text::buf
const char * buf
Definition: TextFile.h:77
NPL::SContext::Validate
YF_API TLCIter Validate(TLCIter b, TLCIter e)
遍历记号列表，验证基本合法性：圆括号是否对应。
Definition: SContext.cpp:53
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
YSLib::Drawing::bounds
The boundary is out of the const Rect & bounds
Definition: YDraw.h:127
YSLib::UI::Resize
大小调整。
Definition: YWidgetEvent.h:383
YSLib::UI::Styles::Window
窗口背景。
Definition: YStyle.h:311
YSLib::FilterExceptions
bool FilterExceptions(_func f, const char *desc={}, RecordLevel lv=Alert, ExceptionTracer trace=ExtractAndTrace) ynothrow
调用函数并过滤宿主异常。
Definition: YException.h:202
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:942
yfsig
#define yfsig
展开为表示函数签名的预定义变量的宏。
Definition: ydef.h:702
YSLib::Drawing::ConstBitmapPtr
const Pixel * ConstBitmapPtr
Definition: YGraphics.h:44
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:305
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:168
YCL_Trace_Win32Error
#define YCL_Trace_Win32Error(_lv, _fn, _msg)
跟踪 ::GetLastError 取得的调用状态结果。
Definition: MinGW32.h:153
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:438
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:440
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:114
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
YSLib::YAssert
YAssert(!(v< Deref(a)),"Value less than lower bound found.")
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:996
YSLib::UI::wgt
IWidget & wgt
Definition: YControl.h:112
NPL::Guard
ystdex::any Guard
作用域守护类型。
Definition: NPLA.h:546
ystdex::pvoid
enable_if_t< or_< is_object< _type >, is_void< _type > >::value, void * > pvoid(_type *p)
取 void* 类型的指针。
Definition: addressof.hpp:101
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
Drawing
YCL_HostedUI_XCB
#define YCL_HostedUI_XCB
在宿主用户界面使用 X C 绑定。
Definition: Platform.h:381
YSLib::i
return i
Definition: YCoreUtilities.h:176
scope_guard.hpp
作用域守护。
platform::Descriptions::Debug
Definition: YCommon.h:160
YModules.h
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
YSLib::UI::GetSizeOf
pt pt Y const IWidget &wgt const IWidget &wgt GetSizeOf
无效化：使相对部件的子部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: YWidget.h:161
YSLib::Drawing::g
The boundary is out of the const Graphics & g
Definition: YDraw.h:161
ystdex::unique_raw
std::unique_ptr< _type > unique_raw(_pSrc *p)
Definition: memory.hpp:617
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex::unique_guard
guard< one_shot< _type > > unique_guard(_type f)
Definition: scope_guard.hpp:92