YSTest: HostRenderer.cpp 源文件

YSTest PreAlpha_b800_20170810 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 Nonnull(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(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 while(const auto p_evt = unique_raw(::xcb_wait_for_event(
149 &Deref(wnd.GetNativeHandle().get()).DerefConn()), std::free))
150 {
151 // YSL_DEBUG_DECL_TIMER(tmr, to_string(msg));
152 auto& m(wnd.MessageMap);
153 const auto msg(p_evt->response_type & ~0x80);
154
155 if(msg == XCB_CLIENT_MESSAGE)
156 {
157 auto& cevt(reinterpret_cast<::xcb_client_message_event_t&>(*p_evt));
158
159 if(cevt.type == wnd.WM_PROTOCOLS
160 && cevt.data.data32[0] == wnd.WM_DELETE_WINDOW)
161 break;
162 }
163
164 const auto i(m.find(msg & ~0x80));
165
166 if(i != m.cend())
167 i->second(p_evt.get());
168 }
169 # else
170 yunused(wnd);
171 # if YCL_Win32
172
173 ::MSG msg{nullptr, 0, 0, 0, 0, {0, 0}};
174 int res;
175
176 while((res = ::GetMessageW(&msg, nullptr, 0, 0)) != 0)
177 {
178
179 // XXX: Error ignored.
180 if(res != -1)
181 {
182 ::TranslateMessage(&msg);
183 ::DispatchMessageW(&msg);
184 }
185 else
186 YCL_Trace_Win32E(Warning, GetMessageW, yfsig);
187 }
188 # endif
189 # endif
190 YTraceDe(Informative, "Host loop ended.");
191 }
192 void
193 WindowThread::WindowLoop(Window& wnd, GuardGenerator gd_gen)
194 {
195 const auto gd(gd_gen ? gd_gen(wnd) : Guard());
196
197 WindowLoop(wnd);
198 }
199
200
201 HostRenderer::~HostRenderer()
202 {
203 #if YCL_Win32
204 FilterExceptions([this]{
205 try
206 {
207 auto& wnd(Wait());
208
209 wnd.GetGUIHostRef().Desktop -= widget;
210 if(const auto p_wgt = dynamic_cast<UI::Widget*>(&widget.get()))
211 p_wgt->SetView({});
212 }
213 CatchIgnore(Windows::UI::ViewSignal&)
214 }, yfsig);
215 #endif
216 }
217
218 void
219 HostRenderer::SetSize(const Size& s)
220 {
221 BufferedRenderer::SetSize(s),
222 Deref(rbuf.Lock()).Resize(s);
223 }
224
225 bool
226 HostRenderer::AdjustSize()
227 {
228 const auto& view_size(GetSizeOf(widget));
229 const auto& buf_size(GetContext().GetSize());
230
231 if(YB_UNLIKELY(view_size != buf_size))
232 {
233 YTraceDe(Warning, "Mismatched host renderer buffer size %s found.",
234 to_string(buf_size).c_str());
235 SetSize(view_size);
236 YTraceDe(Warning, "Host renderer buffer size has adjusted to view size"
237 " %s.", to_string(view_size).c_str());
238 return true;
239 }
240 return {};
241 }
242
243 void
244 HostRenderer::InitWidgetView()
245 {
246 #if YCL_Win32
247 auto& wnd(Wait());
248
249 if(const auto p_wgt = dynamic_cast<UI::Widget*>(&widget.get()))
250 p_wgt->SetView(
251 make_unique<Windows::UI::ControlView>(wnd.GetNativeHandle()));
252 wnd.GetGUIHostRef().Desktop += widget;
253 #endif
254 // FIXME: Allow user to specify which kinds of views should be adjusted.
255 auto& view_ref(widget.get().GetView());
256
257 RootMode = typeid(view_ref) == typeid(UI::View);
258 }
259
260 void
261 HostRenderer::RefreshForWidget()
262 {
263 if(const auto p_wnd = GetWindowPtr())
264 {
265 #if YCL_Win32
266 if(!p_wnd->IsMinimized())
267 #else
268 yunused(p_wnd);
269 #endif
270 {
271 // TODO: Determine what should be painted for thumbnail.
272 // TODO: Provide interface for custom painting.
273 AdjustSize();
274
275 auto& wgt(GetWidgetRef());
276 const auto& g(GetContext());
277 const auto r(GetInvalidatedArea());
278
279 if(Validate(wgt, wgt, {g, {}, r}))
280 Update(g.GetBufferPtr(), r);
281 }
282 }
283 }
284
285 void
286 HostRenderer::Update(ConstBitmapPtr p, const Rect& r)
287 {
288 YAssertNonnull(p);
289 if(const auto p_wnd = GetWindowPtr())
290 try
291 {
292 auto& view(widget.get().GetView());
293 const auto& view_size(view.GetSize());
294 auto p_buf(rbuf.Lock());
295 auto& buf(Deref(p_buf));
296 const auto& buf_size(buf.GetSize());
297
298 if(YB_UNLIKELY(view_size != buf_size))
299 throw LoggedEvent(ystdex::sfmt("Mismatched host renderer buffer"
300 " size %s and view size %s found.",
301 to_string(buf_size).c_str(), to_string(view_size).c_str()));
302 if(RootMode)
303 {
304 # if YCL_HostedUI_XCB
305 const Rect& cbounds(p_wnd->GetBounds());
306 # elif YCL_Android
307 const Rect cbounds(p_wnd->GetSize());
308 # else
309 const Rect& cbounds(p_wnd->GetClientBounds());
310 # endif
311 auto bounds(cbounds);
312 const auto& loc(view.GetLocation());
313
314 if(!loc.IsZero())
315 {
316 bounds.GetPointRef() += loc;
317 view.SetLocation({});
318 rInvalidated = {{}, bounds.GetSize()};
319 Validate(widget, widget, {GetContext(), {}, rInvalidated});
320 }
321 bounds.GetSizeRef() = view_size;
322 # if !YCL_Android
323 if(bounds != cbounds)
324 # if YCL_HostedUI_XCB
325 p_wnd->SetBounds(bounds);
326 # else
327 p_wnd->SetClientBounds(bounds);
328 # endif
329 # endif
330 }
331 #if YCL_Win32
332 p_wnd->UpdateFromBounds(p, buf, r, r.GetPoint());
333 #else
334 yunused(r);
335 p_wnd->UpdateFrom(p, buf);
336 #endif
337 }
338 // TODO: Trace?
339 # if YCL_Win32
340 CatchIgnore(Win32Exception&)
341 # else
342 CatchIgnore(Exception&) // XXX: Use proper platform-dependent type.
343 # endif
344 CatchExpr(LoggedEvent& e, ExtractAndTrace(e, Warning))
345 }
346
347 Window&
348 HostRenderer::Wait()
349 {
350 observer_ptr<Host::Window> p_wnd;
351
352 // XXX: Busy wait.
353 while(!p_wnd)
354 p_wnd = GetWindowPtr();
355 return *p_wnd;
356 }
357
358 } // namespace Host;
359 #endif
360
361 } // namespace YSLib;
362
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:313
platform::Descriptions::Debug
Definition: YCommon.h:170
YSLib::UI::ynothrow
AView &y ynothrow
Definition: YWidgetView.cpp:47
platform::msg
const string & msg
Definition: Debug.h:464
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:451
yfsig
#define yfsig
展开为表示函数签名的预定义变量的宏。
Definition: ydef.h:728
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
YCL_HostedUI_XCB
#define YCL_HostedUI_XCB
在宿主用户界面使用 X C 绑定。
Definition: Platform.h:384
YSLib::UI::wgt
IWidget & wgt
Definition: YControl.h:112
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:120
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:464
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:131
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
YSLib::Text::buf
const char * buf
Definition: TextFile.h:81
ystdex::unique_raw
std::unique_ptr< _type > unique_raw(_pSrc *p)
Definition: memory.hpp:740
YSLib::YAssert
YAssert(!(v< Deref(a)),"Value less than lower bound found.")
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1022
NPL::Guard
ystdex::any Guard
作用域守护类型。
Definition: NPLA.h:958
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
YSLib::UI::Resize
大小调整。
Definition: YWidgetEvent.h:383
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
YSLib::Drawing::g
The boundary is out of the const Graphics & g
Definition: YDraw.h:161
YSLib::FilterExceptions
bool FilterExceptions(_func f, const char *desc={}, RecordLevel lv=Alert, ExceptionTracer trace=ExtractAndTrace) ynothrow
调用函数并过滤宿主异常。
Definition: YException.h:203
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1200
YSLib::i
return i
Definition: YCoreUtilities.h:176
Drawing
YSLib::Drawing::GBinaryGroup::get
yconstfn _type & get(GBinaryGroup< _type > &val)
取分量。
Definition: YGDIBase.h:242
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:968
YSLib::UI::e
void e
Definition: YWidget.h:352
YSLib::UI::Styles::Window
窗口背景。
Definition: YStyle.h:311
YModules.h
platform::Nonnull
_type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:422
platform::Descriptions::Warning
Definition: YCommon.h:167
scope_guard.hpp
作用域守护。
platform::Descriptions::Informative
Definition: YCommon.h:169
ystdex::pvoid
enable_if_t< or_< is_object< _type >, is_void< _type > >::value, void * > pvoid(_type *p)
取 void* 类型的指针。
Definition: addressof.hpp:101
YSLib::Drawing::bounds
The boundary is out of the const Rect & bounds
Definition: YDraw.h:127
YSLib::UI::GetSizeOf
pt pt Y const IWidget &wgt const IWidget &wgt GetSizeOf
无效化：使相对部件的子部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: YWidget.h:161
YSLib::ExtractAndTrace
YF_API void ExtractAndTrace(const std::exception &, RecordLevel=Err) ynothrow
使用 TraceException 展开和跟踪异常类型和信息。
YCL_Trace_Win32E
#define YCL_Trace_Win32E(_lv, _fn, _sig)
跟踪 ::GetLastError 取得的调用状态结果。
Definition: MinGW32.h:157
YSLib::Drawing::ConstBitmapPtr
const Pixel * ConstBitmapPtr
Definition: YGraphics.h:44
CHRLib::p
const auto p(d)
NPL::SContext::Validate
YF_API TLCIter Validate(TLCIter b, TLCIter e)
遍历记号列表，验证基本合法性：圆括号是否对应。
Definition: SContext.cpp:53