16
16
17
17
namespace nbl ::ui::xcb
18
18
{
19
- class XCBHandle ;
19
+ class XCBHandle ;
20
20
21
21
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
+ };
49
49
50
50
// 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 {
107
107
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
+
136
116
XCBHandle (core::smart_refctd_ptr<IWindowManagerXCB>&& windowManager):
137
117
m_windowManager (std::move(windowManager)) {
138
118
const auto & xcb = m_windowManager->getXcbFunctionTable ();
139
119
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
+ }
140
144
}
141
145
~XCBHandle () {
142
146
if (m_connection) {
143
- const auto & xcb = m_windowManager->getXcbFunctionTable ();
147
+ const auto & xcb = m_windowManager->getXcbFunctionTable ();
144
148
xcb.pxcb_disconnect (m_connection);
145
149
}
146
150
}
@@ -149,79 +153,64 @@ namespace nbl::ui::xcb
149
153
inline const IWindowManagerXCB::Xcb& getXcbFunctionTable () const { return m_windowManager->getXcbFunctionTable (); }
150
154
inline const IWindowManagerXCB::XcbIcccm& getXcbIcccmFunctionTable () const { return m_windowManager->getXcbIcccmFunctionTable (); }
151
155
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;
177
168
private:
178
169
core::smart_refctd_ptr<IWindowManagerXCB> m_windowManager;
179
170
xcb_connection_t * m_connection = nullptr ;
180
171
};
181
172
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 ();
224
175
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
+ }
225
214
226
215
#endif
227
216
#endif // C_XCB_HANDLER_XCB
0 commit comments