YSTest: HostRenderer.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

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