YSTest: XCB.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

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

- 文件列表
- 文件成员

XCB.cpp
浏览该文件的文档.
1 /*
2 © 2014-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
29 #include "YCLib/YModules.h"
30 #include YFM_YCLib_Platform
31 #if YF_Use_XCB
32 # include YFM_YCLib_XCB
33 # include YFM_YCLib_Mutex
34 # include <xcb/xcb.h>
35 # include <ystdex/addressof.hpp> // for ystdex::pvoid;
36
37 using namespace YSLib;
38 using namespace Drawing;
39 using namespace platform::Concurrency;
40 using ystdex::cast_array;
42 using YSLib::string;
44 using YSLib::string_view;
45
46 namespace platform_ex
47 {
48
49 namespace XCB
50 {
51
53 static_assert(std::is_same<Atom::NativeType, ::xcb_atom_t>(),
54 "Invalid type found.");
56 static_assert(ystdex::and_<std::is_same<WindowData::ID, ::xcb_window_t>,
57 std::is_same<WindowData::ID, ::xcb_drawable_t>>(),
58 "Invalid type found.");
59
61 namespace
62 {
63
65 using GlobalTable = map<::xcb_connection_t*, map<string, Atom>>;
66
68 shared_ptr<GlobalTable>
69 FetchGlobalTablePtr()
70 {
71 static auto p(make_shared<GlobalTable>());
72
73 return p;
74 }
75
77
78 static mutex TableMutex;
79
81 GlobalTable&
82 FetchGlobalTableRef()
83 {
84 return Deref(FetchGlobalTablePtr());
85 }
86
88 pair<string, Atom>
89 MakeAtomPair(::xcb_connection_t& c_ref, string_view name, bool e) ynothrowv
90 {
91 return pair<string, Atom>{name, Atom(c_ref, name, e)};
92 }
93
94 locked_ptr<map<string, Atom>>
95 LockAtoms(::xcb_connection_t& c_ref)
96 {
97 return {&FetchGlobalTableRef().at(&c_ref), TableMutex};
98 }
100
101
103
104 class XCBConnectionErrorCategory : public std::error_category
105 {
106 public:
107 PDefH(const char*, name, ) const ynothrow override
108 ImplRet("XCBConnectionError")
109 std::string
110 message(int) const override;
111 };
112
113 std::string
114 XCBConnectionErrorCategory::message(int err) const
115 {
116 switch(err)
117 {
118 case XCB_CONN_ERROR:
119 return
120 "connection errors because of socket, pipe and other stream errors";
121 case XCB_CONN_CLOSED_EXT_NOTSUPPORTED:
122 return "shutdown because of extension not supported";
123 case XCB_CONN_CLOSED_MEM_INSUFFICIENT:
124 return "malloc(), calloc() and realloc() error upon failure";
125 case XCB_CONN_CLOSED_REQ_LEN_EXCEED:
126 return "exceeding request length that server accepts";
127 case XCB_CONN_CLOSED_PARSE_ERR:
128 return "error during parsing display string";
129 case XCB_CONN_CLOSED_INVALID_SCREEN:
130 return "the server does not have a screen matching the display";
131 case XCB_CONN_CLOSED_FDPASSING_FAILED:
132 return "some FD passing operation failed";
133 default:
134 return "unknown";
135 }
136 }
138
139
140 class XCBErrorCategory : public std::error_category
141 {
142 public:
143 PDefH(const char*, name, ) const ynothrow override
144 ImplRet("XCBError")
146 std::string
147 message(int) const override;
148 };
149
150 std::string
151 XCBErrorCategory::message(int err) const
152 {
153 return std::string("XCB ") + [&]()->const char*{
154 switch(err)
155 {
156 # define YCL_Impl_XCB_ErrCategory(_x) \
157 case XCB_##_x: \
158 return #_x;
159 YCL_Impl_XCB_ErrCategory(REQUEST)
160 YCL_Impl_XCB_ErrCategory(VALUE)
161 YCL_Impl_XCB_ErrCategory(WINDOW)
162 YCL_Impl_XCB_ErrCategory(PIXMAP)
163 YCL_Impl_XCB_ErrCategory(ATOM)
164 YCL_Impl_XCB_ErrCategory(CURSOR)
165 YCL_Impl_XCB_ErrCategory(FONT)
166 YCL_Impl_XCB_ErrCategory(MATCH)
167 YCL_Impl_XCB_ErrCategory(DRAWABLE)
168 YCL_Impl_XCB_ErrCategory(ACCESS)
169 YCL_Impl_XCB_ErrCategory(ALLOC)
170 YCL_Impl_XCB_ErrCategory(COLORMAP)
171 YCL_Impl_XCB_ErrCategory(G_CONTEXT)
172 YCL_Impl_XCB_ErrCategory(ID_CHOICE)
173 YCL_Impl_XCB_ErrCategory(NAME)
174 YCL_Impl_XCB_ErrCategory(LENGTH)
175 YCL_Impl_XCB_ErrCategory(IMPLEMENTATION)
176 # undef YCL_Impl_XCB_ErrCategory
177 default:
178 return "unknown";
179 }
180 }() + " error";
181 }
182
183
185 const XCBConnectionErrorCategory&
186 FetchXCBConnectionErrorCategory()
187 {
188 static const XCBConnectionErrorCategory ecat{};
189
190 return ecat;
191 }
192
193 const XCBErrorCategory&
194 FetchXCBErrorCategory()
195 {
196 static const XCBErrorCategory ecat{};
197
198 return ecat;
199 }
200
202
203 template<typename _tParam>
204 YB_NORETURN void
205 ThrowGeneralXCBException(_tParam&& arg, int err = 0, const std::error_category&
206 ecat = FetchXCBErrorCategory(), RecordLevel lv = Err)
207 {
208 throw Exception(err, ecat, yforward(arg), lv);
209 }
210
211 void
212 CheckRequest(::xcb_connection_t& c_ref, ::xcb_void_cookie_t cookie,
213 RecordLevel lv = Err)
214 {
215 if(const auto p
216 = unique_raw(::xcb_request_check(&c_ref, cookie), std::free))
217 throw XCBException("xcb_request_check", p->response_type, p->error_code,
218 p->sequence, p->resource_id, p->minor_code, p->major_code,
219 p->full_sequence, lv);
220 }
221
222 unique_ptr<::xcb_get_geometry_reply_t, void(&)(void*)>
223 FetchGeometry(::xcb_connection_t& c_ref, ::xcb_drawable_t id,
224 RecordLevel lv = Err)
225 {
226 const auto cookie(::xcb_get_geometry(&c_ref, id));
227 ::xcb_generic_error_t* p_err{};
228 auto p_reply(unique_raw(::xcb_get_geometry_reply(&c_ref, cookie, &p_err),
229 std::free));
230
231 if(const auto p = unique_raw(p_err, std::free))
232 throw XCBException("xcb_get_geometry_reply", p->response_type,
233 p->error_code, p->sequence, p->resource_id, p->minor_code,
234 p->major_code, p->full_sequence, lv);
235 if(YB_UNLIKELY(!p_reply))
236 ThrowGeneralXCBException("XCB reply is null without error detected.");
237 return p_reply;
238 }
240
241 } // unnamed namespace;
242
243
244 XCBException::XCBException(const char* msg, std::uint8_t resp,
245 std::uint8_t ec, std::uint16_t seq, std::uint32_t rid, std::uint16_t minor,
246 std::uint8_t major, std::uint32_t full_seq, RecordLevel lv)
247 : Exception(resp, FetchXCBErrorCategory(), msg, lv),
248 error_code(ec), sequence(seq), resource_id(rid), minor_code(minor),
249 major_code(major), full_sequence(full_seq)
250 {}
251 XCBException::XCBException(string_view msg, std::uint8_t resp,
252 std::uint8_t ec, std::uint16_t seq, std::uint32_t rid, std::uint16_t minor,
253 std::uint8_t major, std::uint32_t full_seq, RecordLevel lv)
254 : Exception(resp, FetchXCBErrorCategory(), msg, lv),
255 error_code(ec), sequence(seq), resource_id(rid), minor_code(minor),
256 major_code(major), full_sequence(full_seq)
257 {}
258
259
260 int
261 ConnectionReference::GetError() const ynothrow
262 {
263 return ::xcb_connection_has_error(Nonnull(get())) != 0;
264 }
265 void
266 ConnectionReference::Check() const
267 {
268 const int err(GetError());
269
270 if(err != 0)
271 ThrowGeneralXCBException("XCB connection check failed.",
272 err, FetchXCBConnectionErrorCategory());
273 }
274
275 int
276 ConnectionReference::GetFileDescriptor() const ynothrow
277 {
278 return ::xcb_get_file_descriptor(Nonnull(get()));
279 }
280 const ::xcb_setup_t&
281 ConnectionReference::GetSetup() const
282 {
283 if(const auto p = get())
284 {
285 if(const auto p_setup = ::xcb_get_setup(p))
286 return *p_setup;
287 ThrowGeneralXCBException("Getting XCB setup failed.");
288 }
289 ThrowGeneralXCBException("Accessing XCB connection failed.");
290 }
291
292 std::uint32_t
293 ConnectionReference::GenerateID() const ynothrow
294 {
295 return ::xcb_generate_id(Nonnull(get()));
296 }
297
298
299 Connection::Connection(const char* disp_name, int* p_scr)
300 : Connection({}, disp_name, p_scr)
301 {}
302 Connection::Connection(::xcb_auth_info_t* p_auth, const char* disp_name,
303 int* p_scr)
304 : Connection((YTraceDe(Informative, "Creating XCB connection"
305 " with authorization information pointer = %p, display name = '%s',"
306 " screen number = '%s'", ystdex::pvoid(p_auth), disp_name ? disp_name
307 : "[NULL]", p_scr ? to_string(*p_scr).c_str() : "[NULL]"),
308 ::xcb_connect_to_display_with_auth_info(disp_name, p_auth, p_scr)))
309 {}
310 Connection::Connection(ConnectionReference conn_ref)
311 : ConnectionReference(conn_ref),
312 p_shared([this]{
313 if(!get() || IsOnError())
314 ThrowGeneralXCBException("XCB connection failed.",
315 Deref(reinterpret_cast<int*>(get())),
316 FetchXCBConnectionErrorCategory());
317 return FetchGlobalTablePtr();
318 }())
319 {
320 auto& c_ref(Deref(get()));
321 lock_guard<mutex> lck(TableMutex);
322
323 Deref(static_cast<GlobalTable*>(p_shared.get()))[&c_ref]
324 = {MakeAtomPair(c_ref, "WM_PROTOCOLS", true),
325 MakeAtomPair(c_ref, "WM_DELETE_WINDOW", {})};
326 }
327 Connection::~Connection()
328 {
329 {
330 lock_guard<mutex> lck(TableMutex);
331
332 FetchGlobalTableRef().erase(get());
333 }
334 ::xcb_disconnect(Nonnull(get()));
335 }
336
337
338 Atom::Atom(::xcb_connection_t& c_ref, string_view n,
339 bool only_if_exists) ynothrowv
340 : atom([&](::xcb_intern_atom_cookie_t cookie) -> ::xcb_atom_t {
341 if(const auto p = unique_raw(
342 ::xcb_intern_atom_reply(&c_ref, cookie, {}), std::free))
343 return p->atom;
344 return XCB_ATOM_NONE;
345 }(::xcb_intern_atom_unchecked(&c_ref, only_if_exists, n.length(),
346 (Nonnull(n.data()), n.data()))))
347 {}
348
349
350 Atom::NativeType
351 LookupAtom(::xcb_connection_t& c_ref, const string& name)
352 {
353 // TODO: Blocked. Use %string_view as argument using C++14 heterogeneous
354 // %find template.
355 return Deref(LockAtoms(c_ref)).at(name);
356 }
357
358
359 WindowData::WindowData(::xcb_connection_t& c_ref, const Rect& r)
360 : WindowData(c_ref, r, [this, &c_ref]{
361 if(const auto p = ::xcb_setup_roots_iterator(
362 &ConnectionReference(&c_ref).GetSetup()).data)
363 return *p;
364 ThrowGeneralXCBException("No XCB screen found.");
365 }())
366 {}
367 WindowData::WindowData(::xcb_connection_t& c_ref, const Rect& r,
368 const ::xcb_screen_t& scr)
369 : WindowData(c_ref, r, scr.root)
370 {}
371 WindowData::WindowData(::xcb_connection_t& c_ref, const Rect& r,
372 WindowData::ID parent)
373 : Drawable(c_ref)
374 {
375 CheckRequest(c_ref, ::xcb_create_window_checked(&c_ref,
376 XCB_COPY_FROM_PARENT, GetID(), parent, r.X, r.Y, r.Width, r.Height, 0,
377 XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, {}));
378 }
379
380 Rect
381 WindowData::GetBounds() const
382 {
383 auto p_rep(FetchGeometry(DerefConn(), GetID()));
384 auto& rep(Deref(p_rep));
385
386 return {rep.x, rep.y, rep.width, rep.height};
387 }
388
389 void
390 WindowData::SetBounds(const Rect& r)
391 {
392 auto& c_ref(DerefConn());
393 const auto values(cast_array<std::uint32_t>(r.X, r.Y, r.Width, r.Height));
394
395 CheckRequest(c_ref, ::xcb_configure_window_checked(&c_ref, GetID(),
396 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH
397 | XCB_CONFIG_WINDOW_HEIGHT, values.cbegin()));
398 }
399
400 void
401 WindowData::Close()
402 {
403 auto& c_ref(DerefConn());
404 const auto lptr(LockAtoms(c_ref));
405 const auto& atoms(Deref(lptr));
406 ::xcb_client_message_event_t ev{XCB_CLIENT_MESSAGE, 32, 0, GetID(),
407 ::xcb_atom_t(atoms.at("WM_PROTOCOLS")), {}};
408
409 yunseq(ev.data.data32[0] = ::xcb_atom_t(atoms.at("WM_DELETE_WINDOW")),
410 ev.data.data32[1] = XCB_CURRENT_TIME);
411 CheckRequest(c_ref, ::xcb_send_event_checked(&c_ref, {}, GetID(),
412 XCB_EVENT_MASK_PROPERTY_CHANGE, reinterpret_cast<const char*>(&ev)));
413 }
414
415 void
416 WindowData::Hide()
417 {
418 auto& c_ref(DerefConn());
419
420 CheckRequest(c_ref, ::xcb_unmap_window_checked(&c_ref, GetID()));
421 }
422
423 void
424 WindowData::Invalidate(const Rect& r)
425 {
426 auto& c_ref(DerefConn());
427 ::xcb_expose_event_t ev{XCB_EXPOSE, 0, 0, GetID(), std::uint16_t(r.X),
428 std::uint16_t(r.Y), r.Width, r.Height, 0, {0, 0}};
429
430 CheckRequest(c_ref, ::xcb_send_event_checked(&c_ref, {}, GetID(),
431 XCB_EVENT_MASK_EXPOSURE, reinterpret_cast<const char*>(&ev)));
432 }
433
434 void
435 WindowData::Move(const Point& pt)
436 {
437 auto& c_ref(DerefConn());
438 const auto values(cast_array<std::uint32_t>(pt.X, pt.Y));
439
440 CheckRequest(c_ref, ::xcb_configure_window_checked(&c_ref, GetID(),
441 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values.cbegin()));
442 }
443
444 void
445 WindowData::Resize(const Size& s)
446 {
447 auto& c_ref(DerefConn());
448 const auto values(cast_array<std::uint32_t>(s.Width, s.Height));
449
450 CheckRequest(c_ref, ::xcb_configure_window_checked(&c_ref, GetID(),
451 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values.cbegin()));
452 }
453
454 void
455 WindowData::Show()
456 {
457 auto& c_ref(DerefConn());
458
459 CheckRequest(c_ref, ::xcb_map_window_checked(&c_ref, GetID()));
460 }
461
462
463 GContext::~GContext()
464 {
465 ::xcb_free_gc_checked(&DerefConn(), GetID());
466 }
467
468
469 void
470 UpdatePixmapBuffer(WindowData& wnd, const YSLib::Drawing::Rect& r,
471 const ConstGraphics& g)
472 {
473 auto& c_ref(wnd.DerefConn());
474 GContext gc(c_ref);
475
476 CheckRequest(c_ref, ::xcb_put_image_checked(&c_ref,
477 XCB_IMAGE_FORMAT_Z_PIXMAP, wnd.GetID(), gc.GetID(), r.Width, r.Height,
478 r.X, r.Y, 0, Pixel::Traits::XYZBitsN, g.GetSizeOfBuffer(),
479 reinterpret_cast<const byte*>(g.GetBufferPtr())));
480 }
481
482 } // namespace XCB;
483
484 } // namespace platform_ex;
485
486 #endif
487
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:313
YSLib::UI::Move
移动：位置调整。
Definition: YWidgetEvent.h:382
platform::ID
std::uintmax_t ID
YF_Platform_* 宏替换值的公共类型。
Definition: YCommon.h:52
platform::msg
const string & msg
Definition: Debug.h:464
ystdex::cast_array
common_array_t< _type, _tParams... > cast_array(_tParams &&...args)
构造指定参数转换初始化的 std::array 对象。
Definition: array.hpp:58
YSLib::Drawing::GBinaryGroup::Y
_type Y
分量。
Definition: YGDIBase.h:63
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:451
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
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
YSLib::UI::Close
void Close(IWidget &wgt)
Definition: YWidget.cpp:92
platform::containers::string
basic_string< char > string
Definition: Container.h:101
ystdex::unique_raw
std::unique_ptr< _type > unique_raw(_pSrc *p)
Definition: memory.hpp:740
ystdex::data
auto data(_tRange &c) -> decltype(c.data())
Definition: range.hpp:280
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: YGDIBase.h:278
YSLib::Drawing::ConstGraphics
GGraphics< ConstBitmapPtr > ConstGraphics
Definition: YGraphics.h:160
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1022
YSLib::UI::Invalidate
YF_API void Invalidate(IWidget &, const Rect &)
无效化：使相对部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: YWidget.cpp:108
YSLib::RecordLevel
YF_API RecordLevel
Definition: YException.h:142
platform::Descriptions::RecordLevel
RecordLevel
记录等级。
Definition: YCommon.h:161
YSLib::UI::Resize
大小调整。
Definition: YWidgetEvent.h:383
YSLib::Drawing::Size::Width
SDst Width
Definition: YGDIBase.h:302
YSLib::Drawing::g
The boundary is out of the const Graphics & g
Definition: YDraw.h:161
ystdex::path::to_string
_tSeqCon::value_type to_string(const path< _tSeqCon, _tTraits > &pth, const typename _tSeqCon::value_type &seperator=&to_array< typename string_traits< typename _tSeqCon::value_type >::value_type >("/")[0])
取字符串表示。
Definition: path.hpp:340
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:766
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex
特性测试宏。
Definition: ydef.h:822
Drawing
YModules.h
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:168
platform::Concurrency
Definition: Mutex.h:53
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:786
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
addressof.hpp
一元操作符 & 和取指针的相关接口。
YSLib::UI::Show
YF_API void Show(IWidget &)
显示部件。
Definition: YWidget.cpp:202
YSLib::Drawing::Rect
屏幕标准矩形：表示屏幕矩形区域。
Definition: YGDIBase.h:540
YSLib::Drawing::Size::Height
SDst Height
宽和高。
Definition: YGDIBase.h:302
std
Definition: memory.hpp:1183
YSLib::ImplRet
ImplRet(FetchGlobalInstance().GetGUIHostRef()) YF_API void Execute(GUIApplication &
执行程序主消息循环。
ystdex::byte
unsigned char byte
字节类型。
Definition: ydef.h:834
platform::Nonnull
_type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:422
YB_NORETURN
#define YB_NORETURN
指定无返回值函数。
Definition: ydef.h:504
YSLib::UI::Hide
YF_API void Hide(IWidget &)
隐藏部件。
Definition: YWidget.cpp:100
platform::Descriptions::Err
Definition: YCommon.h:166
platform_ex
平台扩展命名空间。
Definition: Android.h:45
YSLib::UI::name
yconstfn const string & name
Definition: Loader.h:130
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::GBinaryGroup::X
_type X
Definition: YGDIBase.h:63
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:995
YSLib::Drawing::PDefH
yconstfn PDefH(Size, Transpose, const Size &s) ynothrow ImplRet(
转置。
Definition: YGDIBase.h:516
ystdex::and_
逻辑操作元函数。
Definition: type_traits.hpp:420
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
CHRLib::p
const auto p(d)
YSLib::lv
RecordLevel lv
Definition: YException.cpp:58