Skip to content

Commit 916a8e0

Browse files
committed
simplify interface
Signed-off-by: Michael Pollind <mpollind@gmail.com>
1 parent 9905d15 commit 916a8e0

File tree

3 files changed

+175
-188
lines changed

3 files changed

+175
-188
lines changed

include/nbl/ui/XCBHandle.h

Lines changed: 169 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -16,131 +16,135 @@
1616

1717
namespace nbl::ui::xcb
1818
{
19-
class XCBHandle;
19+
class XCBHandle;
2020

2121
enum MotifFlags: uint32_t {
22-
MWM_HINTS_NONE = 0,
23-
MWM_HINTS_FUNCTIONS = (1L << 0),
24-
MWM_HINTS_DECORATIONS = (1L << 1),
25-
MWM_HINTS_INPUT_MODE = (1L << 2),
26-
MWM_HINTS_STATUS = (1L << 3),
27-
};
28-
29-
enum MotifFunctions: uint32_t {
30-
MWM_FUNC_NONE = 0,
31-
MWM_FUNC_ALL = (1L << 0),
32-
MWM_FUNC_RESIZE = (1L << 1),
33-
MWM_FUNC_MOVE = (1L << 2),
34-
MWM_FUNC_MINIMIZE = (1L << 3),
35-
MWM_FUNC_MAXIMIZE = (1L << 4),
36-
MWM_FUNC_CLOSE = (1L << 5),
37-
};
38-
39-
enum MotifDecorations: uint32_t {
40-
MWM_DECOR_NONE = 0,
41-
MWM_DECOR_ALL = (1L << 0),
42-
MWM_DECOR_BORDER = (1L << 1),
43-
MWM_DECOR_RESIZEH = (1L << 2),
44-
MWM_DECOR_TITLE = (1L << 3),
45-
MWM_DECOR_MENU = (1L << 4),
46-
MWM_DECOR_MINIMIZE = (1L << 5),
47-
MWM_DECOR_MAXIMIZE = (1L << 6),
48-
};
22+
MWM_HINTS_NONE = 0,
23+
MWM_HINTS_FUNCTIONS = (1L << 0),
24+
MWM_HINTS_DECORATIONS = (1L << 1),
25+
MWM_HINTS_INPUT_MODE = (1L << 2),
26+
MWM_HINTS_STATUS = (1L << 3),
27+
};
28+
29+
enum MotifFunctions: uint32_t {
30+
MWM_FUNC_NONE = 0,
31+
MWM_FUNC_ALL = (1L << 0),
32+
MWM_FUNC_RESIZE = (1L << 1),
33+
MWM_FUNC_MOVE = (1L << 2),
34+
MWM_FUNC_MINIMIZE = (1L << 3),
35+
MWM_FUNC_MAXIMIZE = (1L << 4),
36+
MWM_FUNC_CLOSE = (1L << 5),
37+
};
38+
39+
enum MotifDecorations: uint32_t {
40+
MWM_DECOR_NONE = 0,
41+
MWM_DECOR_ALL = (1L << 0),
42+
MWM_DECOR_BORDER = (1L << 1),
43+
MWM_DECOR_RESIZEH = (1L << 2),
44+
MWM_DECOR_TITLE = (1L << 3),
45+
MWM_DECOR_MENU = (1L << 4),
46+
MWM_DECOR_MINIMIZE = (1L << 5),
47+
MWM_DECOR_MAXIMIZE = (1L << 6),
48+
};
4949

5050
// insane magic in xcb for window hinting good luck finding documentation
51-
// https://fossies.org/linux/motif/lib/Xm/MwmUtil.h
52-
struct MotifWmHints {
53-
MotifFlags flags = MotifFlags::MWM_HINTS_NONE;
54-
MotifFunctions functions = MotifFunctions::MWM_FUNC_NONE;
55-
MotifDecorations decorations = MotifDecorations::MWM_DECOR_NONE;
56-
uint32_t input_mode = 0; // unused
57-
uint32_t status = 0; // unused
58-
};
59-
60-
inline MotifWmHints createFlagsToMotifWmHints(IWindow::E_CREATE_FLAGS flags) {
61-
core::bitflag<MotifFlags> motifFlags(MWM_HINTS_NONE);
62-
core::bitflag<MotifFunctions> motifFunctions(MWM_FUNC_NONE);
63-
core::bitflag<MotifDecorations> motifDecorations(MWM_DECOR_NONE);
64-
motifFlags |= MWM_HINTS_DECORATIONS;
65-
66-
if (flags & IWindow::ECF_BORDERLESS) {
67-
motifDecorations |= MWM_DECOR_ALL;
68-
} else {
69-
motifDecorations |= MWM_DECOR_BORDER;
70-
motifDecorations |= MWM_DECOR_RESIZEH;
71-
motifDecorations |= MWM_DECOR_TITLE;
72-
73-
// minimize button
74-
if(flags & IWindow::ECF_MINIMIZED) {
75-
motifDecorations |= MWM_DECOR_MINIMIZE;
76-
motifFunctions |= MWM_FUNC_MINIMIZE;
77-
}
78-
79-
// maximize button
80-
if(flags & IWindow::ECF_MAXIMIZED) {
81-
motifDecorations |= MWM_DECOR_MAXIMIZE;
82-
motifFunctions |= MWM_FUNC_MAXIMIZE;
83-
}
84-
85-
// close button
86-
motifFunctions |= MWM_FUNC_CLOSE;
87-
}
88-
89-
if(motifFunctions.value != MWM_FUNC_NONE) {
90-
motifFlags |= MWM_HINTS_FUNCTIONS;
91-
motifFunctions |= MWM_FUNC_RESIZE;
92-
motifFunctions |= MWM_FUNC_MOVE;
93-
} else {
94-
motifFunctions = MWM_FUNC_ALL;
95-
}
96-
97-
MotifWmHints hints;
98-
hints.flags = motifFlags.value;
99-
hints.functions = motifFunctions.value;
100-
hints.decorations = motifDecorations.value;
101-
hints.input_mode = 0;
102-
hints.status = 0;
103-
return hints;
104-
}
105-
106-
class XCBHandle final : public core::IReferenceCounted {
51+
// https://fossies.org/linux/motif/lib/Xm/MwmUtil.h
52+
struct MotifWmHints {
53+
MotifFlags flags = MotifFlags::MWM_HINTS_NONE;
54+
MotifFunctions functions = MotifFunctions::MWM_FUNC_NONE;
55+
MotifDecorations decorations = MotifDecorations::MWM_DECOR_NONE;
56+
uint32_t input_mode = 0; // unused
57+
uint32_t status = 0; // unused
58+
};
59+
60+
inline MotifWmHints createFlagsToMotifWmHints(IWindow::E_CREATE_FLAGS flags) {
61+
core::bitflag<MotifFlags> motifFlags(MWM_HINTS_NONE);
62+
core::bitflag<MotifFunctions> motifFunctions(MWM_FUNC_NONE);
63+
core::bitflag<MotifDecorations> motifDecorations(MWM_DECOR_NONE);
64+
motifFlags |= MWM_HINTS_DECORATIONS;
65+
66+
if (flags & IWindow::ECF_BORDERLESS) {
67+
motifDecorations |= MWM_DECOR_ALL;
68+
} else {
69+
motifDecorations |= MWM_DECOR_BORDER;
70+
motifDecorations |= MWM_DECOR_RESIZEH;
71+
motifDecorations |= MWM_DECOR_TITLE;
72+
73+
// minimize button
74+
if(flags & IWindow::ECF_MINIMIZED) {
75+
motifDecorations |= MWM_DECOR_MINIMIZE;
76+
motifFunctions |= MWM_FUNC_MINIMIZE;
77+
}
78+
79+
// maximize button
80+
if(flags & IWindow::ECF_MAXIMIZED) {
81+
motifDecorations |= MWM_DECOR_MAXIMIZE;
82+
motifFunctions |= MWM_FUNC_MAXIMIZE;
83+
}
84+
85+
// close button
86+
motifFunctions |= MWM_FUNC_CLOSE;
87+
}
88+
89+
if(motifFunctions.value != MWM_FUNC_NONE) {
90+
motifFlags |= MWM_HINTS_FUNCTIONS;
91+
motifFunctions |= MWM_FUNC_RESIZE;
92+
motifFunctions |= MWM_FUNC_MOVE;
93+
} else {
94+
motifFunctions = MWM_FUNC_ALL;
95+
}
96+
97+
MotifWmHints hints;
98+
hints.flags = motifFlags.value;
99+
hints.functions = motifFunctions.value;
100+
hints.decorations = motifDecorations.value;
101+
hints.input_mode = 0;
102+
hints.status = 0;
103+
return hints;
104+
}
105+
106+
class XCBHandle final : public core::IReferenceCounted {
107107
public:
108-
template<core::StringLiteral Name>
109-
struct AtomToken {
110-
private:
111-
AtomToken(XCBHandle& handle) : m_handle(handle) {}
112-
XCBHandle& m_handle;
113-
xcb_atom_t m_token = 0;
114-
bool fetched = false;
115-
public:
116-
inline xcb_atom_t fetch(bool only_if_exists = true,
117-
bool forced = false) {
118-
const auto& xcb = m_handle.getXcbFunctionTable();
119-
if(fetched && !forced) {
120-
return m_token;
121-
}
122-
fetched = true;
123-
size_t size = Name.size() - 1; // -1 to remove the null terminator
124-
xcb_intern_atom_cookie_t cookie = xcb.pxcb_intern_atom(m_handle, only_if_exists, size, Name.value);
125-
if(xcb_intern_atom_reply_t* reply = xcb.pxcb_intern_atom_reply(m_handle, cookie, nullptr)) {
126-
m_token = reply->atom;
127-
free(reply);
128-
return m_token;
129-
}
130-
return m_token;
131-
}
132-
133-
friend class XCBHandle;
134-
};
135-
108+
struct XCBHandleToken {
109+
private:
110+
xcb_atom_t m_token = 0;
111+
public:
112+
inline operator xcb_atom_t() { return m_token;}
113+
friend class XCBHandle;
114+
};
115+
136116
XCBHandle(core::smart_refctd_ptr<IWindowManagerXCB>&& windowManager):
137117
m_windowManager(std::move(windowManager)) {
138118
const auto& xcb = m_windowManager->getXcbFunctionTable();
139119
m_connection = xcb.pxcb_connect(nullptr, nullptr);
120+
121+
struct {
122+
const char* name;
123+
XCBHandleToken* token;
124+
} handles[] = {
125+
{"WM_DELETE_WINDOW", &WM_DELETE_WINDOW},
126+
{"WM_PROTOCOLS", &WM_PROTOCOLS},
127+
{"_NET_WM_PING", &_NET_WM_PING},
128+
{"_NET_WM_STATE_MAXIMIZED_VERT", &_NET_WM_STATE_MAXIMIZED_VERT},
129+
{"_NET_WM_STATE_MAXIMIZED_HORZ", &_NET_WM_STATE_MAXIMIZED_HORZ},
130+
{"_NET_WM_STATE_FULLSCREEN", &_NET_WM_STATE_FULLSCREEN},
131+
{"_NET_WM_STATE", &_NET_WM_STATE},
132+
{"_MOTIF_WM_HINTS", &_MOTIF_WM_HINTS},
133+
{"NET_WM_STATE_ABOVE", &NET_WM_STATE_ABOVE},
134+
};
135+
std::array<xcb_intern_atom_cookie_t, std::size(handles)> cookies;
136+
for(size_t i = 0; i < std::size(handles); ++i) {
137+
cookies[i] = xcb.pxcb_intern_atom(m_connection, false, strlen(handles[i].name), handles[i].name);
138+
}
139+
for (size_t i = 0; i < std::size(handles); ++i) {
140+
xcb_intern_atom_reply_t *reply = xcb.pxcb_intern_atom_reply(m_connection, cookies[i], nullptr);
141+
handles[i].token->m_token = reply->atom;
142+
free(reply);
143+
}
140144
}
141145
~XCBHandle() {
142146
if(m_connection) {
143-
const auto& xcb = m_windowManager->getXcbFunctionTable();
147+
const auto& xcb = m_windowManager->getXcbFunctionTable();
144148
xcb.pxcb_disconnect(m_connection);
145149
}
146150
}
@@ -149,79 +153,64 @@ namespace nbl::ui::xcb
149153
inline const IWindowManagerXCB::Xcb& getXcbFunctionTable() const { return m_windowManager->getXcbFunctionTable(); }
150154
inline const IWindowManagerXCB::XcbIcccm& getXcbIcccmFunctionTable() const { return m_windowManager->getXcbIcccmFunctionTable(); }
151155
inline operator xcb_connection_t*() { return m_connection; }
152-
inline xcb_connection_t* getNativeHandle() { return m_connection; }
153-
154-
155-
AtomToken<core::StringLiteral("WM_DELETE_WINDOW")> WM_DELETE_WINDOW{*this};
156-
AtomToken<core::StringLiteral("WM_PROTOCOLS")> WM_PROTOCOLS{*this};
157-
AtomToken<core::StringLiteral("_NET_WM_PING")> _NET_WM_PING{*this};
158-
159-
AtomToken<core::StringLiteral("_NET_WM_STATE_MAXIMIZED_VERT")> _NET_WM_STATE_MAXIMIZED_VERT{*this};
160-
AtomToken<core::StringLiteral("_NET_WM_STATE_MAXIMIZED_HORZ")> _NET_WM_STATE_MAXIMIZED_HORZ{*this};
161-
AtomToken<core::StringLiteral("_NET_WM_STATE_FULLSCREEN")> _NET_WM_STATE_FULLSCREEN{*this};
162-
AtomToken<core::StringLiteral("_NET_WM_STATE")> _NET_WM_STATE{*this};
163-
AtomToken<core::StringLiteral("_MOTIF_WM_HINTS")> _MOTIF_WM_HINTS{*this};
164-
AtomToken<core::StringLiteral("NET_WM_STATE_ABOVE")> NET_WM_STATE_ABOVE{*this};
165-
166-
AtomToken<core::StringLiteral("CLIPBOARD")> m_CLIPBOARD{*this};
167-
AtomToken<core::StringLiteral("TARGETS")> m_TARGETS{*this};
168-
AtomToken<core::StringLiteral("INCR")> m_INCR{*this};
169-
170-
AtomToken<core::StringLiteral("UTF8_STRING")> m_formatUTF8_0{*this};
171-
AtomToken<core::StringLiteral("text/plain;charset=utf-8")> m_formatUTF8_1{*this};
172-
AtomToken<core::StringLiteral("text/plain;charset=UTF-8")> m_formatUTF8_2{*this};
173-
AtomToken<core::StringLiteral("GTK_TEXT_BUFFER_CONTENTS")> m_formatGTK{*this};
174-
AtomToken<core::StringLiteral("STRING")> m_formatString{*this};
175-
AtomToken<core::StringLiteral("TEXT")> m_formatText{*this};
176-
AtomToken<core::StringLiteral("text/plain")> m_formatTextPlain{*this};
156+
inline xcb_connection_t* getNativeHandle() { return m_connection; }
157+
158+
XCBHandleToken WM_DELETE_WINDOW;
159+
XCBHandleToken WM_PROTOCOLS;
160+
XCBHandleToken _NET_WM_PING;
161+
162+
XCBHandleToken _NET_WM_STATE_MAXIMIZED_VERT;
163+
XCBHandleToken _NET_WM_STATE_MAXIMIZED_HORZ;
164+
XCBHandleToken _NET_WM_STATE_FULLSCREEN;
165+
XCBHandleToken _NET_WM_STATE;
166+
XCBHandleToken _MOTIF_WM_HINTS;
167+
XCBHandleToken NET_WM_STATE_ABOVE;
177168
private:
178169
core::smart_refctd_ptr<IWindowManagerXCB> m_windowManager;
179170
xcb_connection_t* m_connection = nullptr;
180171
};
181172

182-
inline void setMotifWmHints(XCBHandle& handle, xcb_window_t window, const MotifWmHints& hint) {
183-
auto& xcb = handle.getXcbFunctionTable();
184-
185-
auto atomHint = handle._MOTIF_WM_HINTS.fetch();
186-
if(hint.flags != MotifFlags::MWM_HINTS_NONE) {
187-
xcb.pxcb_change_property(handle.getNativeHandle(), XCB_PROP_MODE_REPLACE, window,
188-
atomHint,
189-
atomHint, 32, sizeof(MotifWmHints) / sizeof(uint32_t), &hint);
190-
} else {
191-
xcb.pxcb_delete_property(handle.getNativeHandle(), window, atomHint);
192-
}
193-
}
194-
195-
inline void setNetMWState(XCBHandle& handle, xcb_window_t rootWindow,
196-
xcb_window_t window,
197-
bool set,
198-
xcb_atom_t first,
199-
xcb_atom_t second = XCB_NONE) {
200-
auto& xcb = handle.getXcbFunctionTable();
201-
202-
xcb_client_message_event_t event;
203-
event.response_type = XCB_CLIENT_MESSAGE;
204-
event.type = handle._NET_WM_STATE.fetch();
205-
event.window = window;
206-
event.format = 32;
207-
event.sequence = 0;
208-
event.data.data32[0] = set ? 1l : 0l;
209-
event.data.data32[1] = first;
210-
event.data.data32[2] = second;
211-
event.data.data32[3] = 1;
212-
event.data.data32[4] = 0;
213-
xcb.pxcb_send_event(handle, 0, rootWindow,
214-
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, reinterpret_cast<const char*>(&event));
215-
}
216-
217-
inline const xcb_screen_t* primaryScreen(XCBHandle& handle) {
218-
auto& xcb = handle.getXcbFunctionTable();
219-
const xcb_setup_t *setup = xcb.pxcb_get_setup(handle);
220-
xcb_screen_t *screen = xcb.pxcb_setup_roots_iterator(setup).data;
221-
return screen;
222-
}
223-
}
173+
inline void setMotifWmHints(XCBHandle& handle, xcb_window_t window, const MotifWmHints& hint) {
174+
auto& xcb = handle.getXcbFunctionTable();
224175

176+
if(hint.flags != MotifFlags::MWM_HINTS_NONE) {
177+
xcb.pxcb_change_property(handle.getNativeHandle(), XCB_PROP_MODE_REPLACE, window,
178+
handle._MOTIF_WM_HINTS,
179+
handle._MOTIF_WM_HINTS, 32, sizeof(MotifWmHints) / sizeof(uint32_t), &hint);
180+
} else {
181+
xcb.pxcb_delete_property(handle.getNativeHandle(), window, handle._MOTIF_WM_HINTS);
182+
}
183+
}
184+
185+
inline void setNetMWState(XCBHandle& handle, xcb_window_t rootWindow,
186+
xcb_window_t window,
187+
bool set,
188+
xcb_atom_t first,
189+
xcb_atom_t second = XCB_NONE) {
190+
auto& xcb = handle.getXcbFunctionTable();
191+
192+
xcb_client_message_event_t event;
193+
event.response_type = XCB_CLIENT_MESSAGE;
194+
event.type = handle._NET_WM_STATE;
195+
event.window = window;
196+
event.format = 32;
197+
event.sequence = 0;
198+
event.data.data32[0] = set ? 1l : 0l;
199+
event.data.data32[1] = first;
200+
event.data.data32[2] = second;
201+
event.data.data32[3] = 1;
202+
event.data.data32[4] = 0;
203+
xcb.pxcb_send_event(handle, 0, rootWindow,
204+
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, reinterpret_cast<const char*>(&event));
205+
}
206+
207+
inline const xcb_screen_t* primaryScreen(XCBHandle& handle) {
208+
auto& xcb = handle.getXcbFunctionTable();
209+
const xcb_setup_t *setup = xcb.pxcb_get_setup(handle);
210+
xcb_screen_t *screen = xcb.pxcb_setup_roots_iterator(setup).data;
211+
return screen;
212+
}
213+
}
225214

226215
#endif
227216
#endif // C_XCB_HANDLER_XCB

0 commit comments

Comments
 (0)