YSTest: GUIApplication.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

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

- 文件列表
- 文件成员

GUIApplication.cpp
浏览该文件的文档.
1 /*
2 © 2012-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_GUIApplication
30 #include YFM_Helper_Environment
31 #include YFM_YCLib_Input // for platform_ex::FetchCursor;
32 #if YCL_Win32
33 # include YFM_Win32_Helper_Win32Control // for Windows::UI::ControlView;
34 #elif YCL_Android
35 # include YFM_Android_Helper_AndroidHost // for Android::NativeHost;
36 #endif
37
38 namespace YSLib
39 {
40
41 using namespace Drawing;
42 #if YF_Hosted
43 using namespace Host;
44 #endif
45
46 namespace
47 {
48
50 recursive_mutex ApplicationMutex;
51
53 GUIApplication* ApplicationPtr;
54
59 inline PDefH(Message, FetchIdleMessage, )
60 ImplRet(Message(SM_Input))
61
66 inline void
67 Idle(Messaging::Priority prior)
68 {
69 // NOTE: Wait for GUI input of any shells. Post message for specific shell
70 // would cause low performance when there are many candidate messages
71 // of distinct shells.
72 PostMessage(FetchIdleMessage(), prior);
73 }
74
75 } // unnamed namespace;
76
77
78 GUIHost::GUIHost()
79 #if YF_Hosted
80 : wnd_map(), wmap_mtx()
81 # if YF_Multithread == 1
82 # if YCL_Win32
83 , window_class(WindowClassName)
84 # endif
85 # endif
86 # if YCL_Android
87 , Desktop(Android::FetchNativeHostInstance().GetHostScreenRef())
88 # endif
89 #endif
90 {
91 #if YCL_Win32
92 Desktop.SetView(
93 make_unique<Windows::UI::ControlView>(::GetDesktopWindow()));
94 Desktop.SetRenderer(make_unique<UI::PseudoRenderer>());
95 #endif
96 YCL_Trace(Debug, "GUI host lifetime began.");
97 }
98 GUIHost::~GUIHost()
99 {
100 YCL_Trace(Debug, "GUI host lifetime ended.");
101
102 # if YF_Hosted && !YCL_Android
103 using ystdex::get_value;
104
105 std::for_each(wnd_map.cbegin() | get_value, wnd_map.cend() | get_value,
106 [](observer_ptr<Window> p) ynothrow{
107 FilterExceptions([&]{
108 p->Close();
109 });
110 });
111 # endif
112 }
113
114 #if YF_Hosted
115 observer_ptr<Window>
116 GUIHost::GetForegroundWindow() const ynothrow
117 {
118 # ifdef YCL_Win32
119 return FindWindow(::GetForegroundWindow());
120 # else
121 return {};
122 # endif
123 }
124
125 void
126 GUIHost::AddMappedItem(NativeWindowHandle h, observer_ptr<Window> p)
127 {
128 lock_guard<mutex> lck(wmap_mtx);
129
130 wnd_map.emplace(h, p);
131 }
132
133 void
134 GUIHost::EnterWindowThread()
135 {
136 ++wnd_thrd_count;
137 }
138
139 observer_ptr<Window>
140 GUIHost::FindWindow(NativeWindowHandle h) const ynothrow
141 {
142 lock_guard<mutex> lck(wmap_mtx);
143 const auto i(wnd_map.find(h));
144
145 return i == wnd_map.end() ? nullptr : i->second;
146 }
147
148 # if YF_Multithread == 1
149 void
150 GUIHost::LeaveWindowThread()
151 {
152 if(--wnd_thrd_count == 0 && ExitOnAllWindowThreadCompleted)
153 YSLib::PostQuitMessage(0);
154 YTraceDe(Debug, "New window thread count = %zu.", wnd_thrd_count.load());
155 }
156 # endif
157
158 pair<observer_ptr<Window>, Point>
159 GUIHost::MapCursor() const
160 {
161 # if YCL_Win32
162 ::POINT cursor;
163
164 if(YB_UNLIKELY(!::GetCursorPos(&cursor)))
165 return {{}, Point::Invalid};
166
167 const Point pt{cursor.x, cursor.y};
168
169 return MapPoint ? MapPoint(pt) : pair<observer_ptr<Window>, Point>({}, pt);
170 # elif YCL_Android
171 // TODO: Support floating point coordinates.
172 const auto& cursor(platform_ex::FetchCursor());
173 const Point pt(cursor.first, cursor.second);
174
175 return {{}, MapPoint ? MapPoint(pt) : pt};
176 # else
177 return {{}, Point::Invalid};
178 # endif
179 }
180
181 # if YCL_Win32
182 pair<observer_ptr<Window>, Point>
183 GUIHost::MapTopLevelWindowPoint(const Point& pt) const
184 {
185 ::POINT cursor{pt.X, pt.Y};
186
187 if(const auto h = ::ChildWindowFromPointEx(::GetDesktopWindow(),
188 cursor, CWP_SKIPINVISIBLE))
189 {
190 auto p_wnd = FindWindow(h);
191
192 if(!p_wnd)
193 p_wnd = GetForegroundWindow();
194 if(p_wnd)
195 {
196 YCL_CallWin32F(ScreenToClient, p_wnd->GetNativeHandle(), &cursor);
197 return {p_wnd, p_wnd->MapPoint({cursor.x, cursor.y})};
198 }
199 }
200 return {{}, Point::Invalid};
201 }
202 # endif
203
204 void
205 GUIHost::RemoveMappedItem(NativeWindowHandle h) ynothrow
206 {
207 lock_guard<mutex> lck(wmap_mtx);
208 const auto i(wnd_map.find(h));
209
210 if(i != wnd_map.end())
211 wnd_map.erase(i);
212 }
213
214 void
215 GUIHost::UpdateRenderWindows()
216 {
217 lock_guard<mutex> lck(wmap_mtx);
218
219 for(const auto& pr : wnd_map)
220 if(pr.second)
221 pr.second->Refresh();
222 }
223 #endif
224
225
226 GUIApplication::InitBlock::InitBlock(Application& app)
227 : p_env(new Environment(app))
228 {}
229
230 GUIApplication::GUIApplication()
231 : Application(), init(*this)
232 {
233 lock_guard<recursive_mutex> lck(ApplicationMutex);
234
235 YAssert(!ApplicationPtr, "Duplicate instance found.");
236 ApplicationPtr = this;
237 }
238
239 GUIApplication::~GUIApplication()
240 {
241 lock_guard<recursive_mutex> lck(ApplicationMutex);
242
243 ApplicationPtr = {};
244 }
245
246 Environment&
247 GUIApplication::GetEnvironmentRef() const ynothrow
248 {
249 return Deref(init.get().p_env);
250 }
251 GUIHost&
252 GUIApplication::GetGUIHostRef() const ynothrow
253 {
254 return init.get().host;
255 }
256
257 bool
258 GUIApplication::DealMessage()
259 {
260 if(AccessQueue([](MessageQueue& mq) ynothrow{
261 return mq.empty();
262 }))
263 // Idle(UIResponseLimit);
264 OnGotMessage(FetchIdleMessage());
265 else
266 {
267 const auto i(AccessQueue([](MessageQueue& mq) ynothrow{
268 return mq.cbegin();
269 }));
270
271 if(YB_UNLIKELY(i->second.GetMessageID() == SM_Quit))
272 return {};
273 if(i->first < UIResponseLimit)
274 Idle(UIResponseLimit);
275 OnGotMessage(i->second);
276 AccessQueue([i](MessageQueue& mq) ynothrowv{
277 mq.erase(i);
278 });
279 }
280 return true;
281 }
282
283
284 GUIApplication&
285 FetchGlobalInstance()
286 {
287 lock_guard<recursive_mutex> lck(ApplicationMutex);
288
289 if(ApplicationPtr)
290 return *ApplicationPtr;
291 throw GeneralEvent("Application instance is not ready.");
292 }
293
294 /* extern */Application&
295 FetchAppInstance()
296 {
297 return FetchGlobalInstance();
298 }
299
300 locked_ptr<GUIApplication, recursive_mutex>
301 LockInstance()
302 {
303 return {ApplicationPtr, ApplicationMutex};
304 }
305
306
307 void
308 Execute(GUIApplication& app, shared_ptr<Shell> p_shl)
309 {
310 #if YF_Hosted
311 FetchGUIHost().ExitOnAllWindowThreadCompleted = true;
312 #endif
313 if(YB_UNLIKELY(!Activate(p_shl)))
314 throw GeneralEvent("Failed activating the main shell.");
315 while(app.DealMessage())
316 ;
317 }
318
319 } // namespace YSLib;
320
platform::p
while p p
Definition: YCLib/FileSystem.h:225
YSLib::Activate
Activate
Definition: YApplication.h:175
YSLib::GUIHost
GUI 宿主。
Definition: GUIApplication.h:57
YSLib::shared_ptr< Shell >
shared_ptr< Shell >
Definition: GUIApplication.h:311
ystdex::get_value
const second_tag get_value
Definition: iterator.hpp:589
YSLib::GeneralEvent
std::runtime_error GeneralEvent
一般运行时异常事件类。
Definition: YException.h:45
YSLib::Execute
void Execute(GUIApplication &app, shared_ptr< Shell > p_shl)
Definition: GUIApplication.cpp:308
YSLib::PostQuitMessage
YF_API void PostQuitMessage(int=0, Messaging::Priority p=DefaultQuitPriority)
以指定错误码和优先级发起 Shell 终止请求。
Definition: YApplication.cpp:85
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
YSLib::Drawing::GBinaryGroup::X
_type X
Definition: YGDIBase.h:63
YSLib::Environment
应用程序环境。
Definition: Environment.h:62
YSLib::UI::Styles::Window
窗口背景。
Definition: YStyle.h:311
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:760
YSLib::FilterExceptions
bool FilterExceptions(_func f, const char *desc={}, RecordLevel lv=Alert, ExceptionTracer trace=ExtractAndTrace) ynothrow
调用函数并过滤宿主异常。
Definition: YException.h:202
YSLib::FetchGUIHost
FetchGUIHost
Definition: GUIApplication.h:300
YSLib::Drawing::PDefH
yconstfn PDefH(Size, Transpose, const Size &s) ynothrow ImplRet(
转置。
Definition: YGDIBase.h:516
YSLib::GUIApplication::GetGUIHostRef
GUIHost & GetGUIHostRef() const ynothrow
Definition: GUIApplication.cpp:252
YCL_CallWin32F
#define YCL_CallWin32F(_fn,...)
Definition: MinGW32.h:179
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:305
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:168
YSLib::GUIApplication::InitBlock::InitBlock
InitBlock(Application &)
Definition: GUIApplication.cpp:226
SM_Input
#define SM_Input
Definition: ymsgdef.h:67
YSLib::Application
程序实例。
Definition: YApplication.h:46
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:438
YSLib::LockInstance
YF_API locked_ptr< yimpl(GUIApplication), recursive_mutex > LockInstance()
锁定实例。
Definition: GUIApplication.cpp:301
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:440
YSLib::GUIApplication::DealMessage
bool DealMessage()
处理当前消息。
Definition: GUIApplication.cpp:258
YSLib::GUIApplication
平台相关的应用程序类。
Definition: GUIApplication.h:202
YCL_Trace
#define YCL_Trace(_lv,...)
YCLib 默认调试跟踪。
Definition: Debug.h:286
YSLib::UI::Styles::Desktop
桌面背景。
Definition: YStyle.h:310
YSLib::YAssert
YAssert(!(v< Deref(a)),"Value less than lower bound found.")
SM_Quit
#define SM_Quit
Definition: ymsgdef.h:62
YSLib::GUIApplication::GetEnvironmentRef
Environment & GetEnvironmentRef() const ynothrow
Definition: GUIApplication.cpp:247
YSLib::GUIApplication::UIResponseLimit
Messaging::Priority UIResponseLimit
用户界面输入响应阈值。
Definition: GUIApplication.h:227
Drawing
YSLib::Application::OnGotMessage
void OnGotMessage(const Message &) override
处理消息：分发消息。
Definition: YApplication.cpp:53
YSLib::GUIApplication::~GUIApplication
~GUIApplication() override
析构：释放资源。
Definition: GUIApplication.cpp:239
YSLib::i
return i
Definition: YCoreUtilities.h:176
YSLib::Drawing::GBinaryGroup< SPos >::Invalid
static const GBinaryGroup Invalid
无效（不在屏幕坐标系中）对象。
Definition: YGDIBase.h:58
YSLib::UI::Desktop
桌面。
Definition: YDesktop.h:46
YSLib::UI::Widget::SetView
void SetView(unique_ptr< AView >)
设置视图为指定指针指向的对象。
Definition: YWidget.cpp:255
platform::Descriptions::Debug
Definition: YCommon.h:160
YSLib::Messaging::Priority
std::uint8_t Priority
消息优先级。
Definition: YMessage.h:51
ystdex::single_thread::lock_guard
Definition: pseudo_mutex.h:197
YModules.h
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: YGDIBase.h:278
YSLib::GUIHost::GUIHost
GUIHost()
Definition: GUIApplication.cpp:78
YSLib::PostMessage
const shared_ptr< Shell > &hShl ImplRet(FetchAppInstance().Switch(shared_ptr< Shell >(hShl))) yconstexpr const Messaging YF_API void PostMessage(const Message &, Messaging::Priority)
默认退出消息优先级。
Definition: YApplication.cpp:77
YSLib::FetchAppInstance
YF_API Application & FetchAppInstance()
取应用程序实例。
Definition: GUIApplication.cpp:295
YSLib::FetchGlobalInstance
_tApp & FetchGlobalInstance()
Definition: GUIApplication.h:274
YSLib::GUIHost::~GUIHost
~GUIHost()
Definition: GUIApplication.cpp:98
YSLib::ImplRet
ImplRet(FetchGlobalInstance().GetGUIHostRef()) YF_API void Execute(GUIApplication &
执行程序主消息循环。
YSLib::GUIApplication::init
ystdex::call_once_init< InitBlock, once_flag > init
Definition: GUIApplication.h:218
YSLib::GUIApplication::GUIApplication
GUIApplication()
private 构造函数：非内联。
Definition: GUIApplication.cpp:230