cae  0.0.0
Cross-API graphics engine
Loading...
Searching...
No Matches
x11.cpp
Go to the documentation of this file.
1#include "X11/X11.hpp"
2
3#include "Utils/Image.hpp"
4#include "Utils/Logger.hpp"
5
6#include <X11/keysym.h>
7
8#include <X11/XKBlib.h>
9#include <utility>
10#include <vector>
11
12static cae::KeyCode translateKeysym(const KeySym sym)
13{
14 switch (sym)
15 {
16 case XK_a:
17 return cae::KeyCode::A;
18 case XK_b:
19 return cae::KeyCode::B;
20 case XK_c:
21 return cae::KeyCode::C;
22 case XK_d:
23 return cae::KeyCode::D;
24 case XK_e:
25 return cae::KeyCode::E;
26 case XK_f:
27 return cae::KeyCode::F;
28 case XK_g:
29 return cae::KeyCode::G;
30 case XK_h:
31 return cae::KeyCode::H;
32 case XK_i:
33 return cae::KeyCode::I;
34 case XK_j:
35 return cae::KeyCode::J;
36 case XK_k:
37 return cae::KeyCode::K;
38 case XK_l:
39 return cae::KeyCode::L;
40 case XK_m:
41 return cae::KeyCode::M;
42 case XK_n:
43 return cae::KeyCode::N;
44 case XK_o:
45 return cae::KeyCode::O;
46 case XK_p:
47 return cae::KeyCode::P;
48 case XK_q:
49 return cae::KeyCode::Q;
50 case XK_r:
51 return cae::KeyCode::R;
52 case XK_s:
53 return cae::KeyCode::S;
54 case XK_t:
55 return cae::KeyCode::T;
56 case XK_u:
57 return cae::KeyCode::U;
58 case XK_v:
59 return cae::KeyCode::V;
60 case XK_w:
61 return cae::KeyCode::W;
62 case XK_x:
63 return cae::KeyCode::X;
64 case XK_y:
65 return cae::KeyCode::Y;
66 case XK_z:
67 return cae::KeyCode::Z;
68
69 // Numbers
70 case XK_0:
71 return cae::KeyCode::Num0;
72 case XK_1:
73 return cae::KeyCode::Num1;
74 case XK_2:
75 return cae::KeyCode::Num2;
76 case XK_3:
77 return cae::KeyCode::Num3;
78 case XK_4:
79 return cae::KeyCode::Num4;
80 case XK_5:
81 return cae::KeyCode::Num5;
82 case XK_6:
83 return cae::KeyCode::Num6;
84 case XK_7:
85 return cae::KeyCode::Num7;
86 case XK_8:
87 return cae::KeyCode::Num8;
88 case XK_9:
89 return cae::KeyCode::Num9;
90
91 // Modifiers
92 case XK_Shift_L:
94 case XK_Shift_R:
96 case XK_Control_L:
98 case XK_Control_R:
100 case XK_Alt_L:
101 return cae::KeyCode::LAlt;
102 case XK_Alt_R:
103 return cae::KeyCode::RAlt;
104 case XK_Super_L:
106 case XK_Super_R:
108 case XK_Caps_Lock:
110
111 // Navigation
112 case XK_Up:
113 return cae::KeyCode::Up;
114 case XK_Down:
115 return cae::KeyCode::Down;
116 case XK_Left:
117 return cae::KeyCode::Left;
118 case XK_Right:
119 return cae::KeyCode::Right;
120 case XK_Home:
121 return cae::KeyCode::Home;
122 case XK_End:
123 return cae::KeyCode::End;
124 case XK_Page_Up:
126 case XK_Page_Down:
128
129 // Editing
130 case XK_Return:
131 return cae::KeyCode::Enter;
132 case XK_BackSpace:
134 case XK_Tab:
135 return cae::KeyCode::Tab;
136 case XK_space:
137 return cae::KeyCode::Space;
138 case XK_Delete:
140 case XK_Insert:
142
143 // Function keys
144 case XK_F1:
145 return cae::KeyCode::F1;
146 case XK_F2:
147 return cae::KeyCode::F2;
148 case XK_F3:
149 return cae::KeyCode::F3;
150 case XK_F4:
151 return cae::KeyCode::F4;
152 case XK_F5:
153 return cae::KeyCode::F5;
154 case XK_F6:
155 return cae::KeyCode::F6;
156 case XK_F7:
157 return cae::KeyCode::F7;
158 case XK_F8:
159 return cae::KeyCode::F8;
160 case XK_F9:
161 return cae::KeyCode::F9;
162 case XK_F10:
163 return cae::KeyCode::F10;
164 case XK_F11:
165 return cae::KeyCode::F11;
166 case XK_F12:
167 return cae::KeyCode::F12;
168
169 // System
170 case XK_Escape:
172 case XK_Print:
174 case XK_Pause:
175 return cae::KeyCode::Pause;
176 case XK_Menu:
177 return cae::KeyCode::Menu;
178
179 default:
180 return cae::KeyCode::Count;
181 }
182}
183
184bool cae::X11::create(const std::string &name, const WindowSize size)
185{
186 m_display = XOpenDisplay(nullptr);
187 if (m_display == nullptr)
188 {
189 utl::Logger::log("Failed to open X display", utl::LogLevel::WARNING);
190 return false;
191 }
192
193 const int screen = DefaultScreen(m_display);
194 const Window root = RootWindow(m_display, screen);
195
196 m_window = XCreateSimpleWindow(m_display, root, 0, 0, size.width, size.height, 1, BlackPixel(m_display, screen),
197 WhitePixel(m_display, screen));
198
199 if (m_window == 0U)
200 {
201 utl::Logger::log("Failed to create X11 window", utl::LogLevel::WARNING);
202 return false;
203 }
204
205 XStoreName(m_display, m_window, name.c_str());
206
207 XSelectInput(m_display, m_window,
208 ExposureMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask | PointerMotionMask |
209 ButtonPressMask | ButtonReleaseMask);
210 m_wmDeleteMessage = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
211 XSetWMProtocols(m_display, m_window, &m_wmDeleteMessage, 1);
212
213 XMapWindow(m_display, m_window);
214 XFlush(m_display);
215
216 m_frameBufferSize = size;
217
218 return true;
219}
220
221void cae::X11::close()
222{
223 if (m_display != nullptr && m_window != 0U)
224 {
225 XDestroyWindow(m_display, m_window);
226 XCloseDisplay(m_display);
227 m_display = nullptr;
228 m_window = 0;
229 }
230}
231
232cae::WindowSize cae::X11::getWindowSize() const
233{
234 if (m_display == nullptr || m_window == 0U)
235 {
236 return m_frameBufferSize;
237 }
238
239 XWindowAttributes attrs;
240 XGetWindowAttributes(m_display, m_window, &attrs);
241 return {.width = static_cast<uint16_t>(attrs.width), .height = static_cast<uint16_t>(attrs.height)};
242}
243
244void cae::X11::setIcon(const std::string &path) const
245{
246 if ((m_display == nullptr) || m_window == 0)
247 {
248 utl::Logger::log("Failed to create window icon", utl::LogLevel::WARNING);
249 return;
250 }
251
252 try
253 {
254 const utl::Image image(path);
255
256 const auto pixelCount = image.width * image.height;
257 std::vector<unsigned long> iconData;
258 iconData.reserve(2 + pixelCount);
259
260 iconData.push_back(static_cast<unsigned long>(image.width));
261 iconData.push_back(static_cast<unsigned long>(image.height));
262
263 const uint8_t *pixels = image.pixels;
264 for (size_t i = 0; std::cmp_less(i, pixelCount); ++i)
265 {
266 const uint8_t r = pixels[(i * 4) + 0];
267 const uint8_t g = pixels[(i * 4) + 1];
268 const uint8_t b = pixels[(i * 4) + 2];
269 const uint8_t a = pixels[(i * 4) + 3];
270
271 const unsigned long argb = (static_cast<unsigned long>(a) << 24) | (static_cast<unsigned long>(r) << 16) |
272 (static_cast<unsigned long>(g) << 8) | (static_cast<unsigned long>(b));
273
274 iconData.push_back(argb);
275 }
276
277 const Atom netWmIcon = XInternAtom(m_display, "_NET_WM_ICON", False);
278 const Atom cardinal = XInternAtom(m_display, "CARDINAL", False);
279
280 XChangeProperty(m_display, m_window, netWmIcon, cardinal, 32, PropModeReplace,
281 reinterpret_cast<const unsigned char *>(iconData.data()), static_cast<int>(iconData.size()));
282
283 XFlush(m_display);
284 }
285 catch (const std::exception &e)
286 {
287 utl::Logger::log(std::string("Failed to set X11 window icon: ") + e.what(), utl::LogLevel::WARNING);
288 }
289}
290
291bool cae::X11::shouldClose() const { return m_shouldClose; }
292
293void cae::X11::pollEvents() {}
294
295bool cae::X11::pollEvent(WindowEvent &outEvent)
296{
297 if (m_eventQueue.empty() && XPending(m_display) == 0)
298 {
299 return false;
300 }
301
302 while (XPending(m_display) > 0)
303 {
304 XEvent event;
305 XNextEvent(m_display, &event);
306 WindowEvent e{};
307
308 switch (event.type)
309 {
310 case KeyPress:
311 {
312 e.type = WindowEventType::KeyDown;
313
314 const KeySym sym = XkbKeycodeToKeysym(m_display, event.xkey.keycode, 0, 0);
315
316 e.key.key = translateKeysym(sym);
317 m_eventQueue.push(e);
318 break;
319 }
320
321 case KeyRelease:
322 {
323 e.type = WindowEventType::KeyUp;
324
325 const KeySym sym = XkbKeycodeToKeysym(m_display, event.xkey.keycode, 0, 0);
326
327 e.key.key = translateKeysym(sym);
328 m_eventQueue.push(e);
329 break;
330 }
331
332 case ConfigureNotify:
333 m_frameBufferResized = true;
334 m_frameBufferSize.width = event.xconfigure.width;
335 m_frameBufferSize.height = event.xconfigure.height;
336 e.type = WindowEventType::Resize;
337 e.resize.w = event.xconfigure.width;
338 e.resize.h = event.xconfigure.height;
339 m_eventQueue.push(e);
340 break;
341
342 case ClientMessage:
343 if (std::cmp_equal(event.xclient.data.l[0], m_wmDeleteMessage))
344 {
345 m_shouldClose = true;
346 e.type = WindowEventType::Close;
347 m_eventQueue.push(e);
348 }
349 break;
350
351 case MotionNotify:
352 e.type = WindowEventType::MouseMove;
353 e.mouseMove.x = event.xmotion.x;
354 e.mouseMove.y = event.xmotion.y;
355 m_eventQueue.push(e);
356 break;
357
358 case ButtonPress:
359 case ButtonRelease:
360 e.type =
361 (event.type == ButtonPress) ? WindowEventType::MouseButtonDown : WindowEventType::MouseButtonUp;
362 e.mouseButton.button = static_cast<MouseButton>(event.xbutton.button);
363 m_eventQueue.push(e);
364 break;
365
366 case Expose:
367 break;
368
369 default:
370 break;
371 }
372 }
373
374 if (!m_eventQueue.empty())
375 {
376 outEvent = m_eventQueue.front();
377 m_eventQueue.pop();
378 return true;
379 }
380
381 return false;
382}
This file contains image struct.
This file contains the Logger class.
static void log(const std::string &message, const LogLevel &logLevel)
Log a message with a specific log level.
Definition Logger.hpp:71
WindowEventType
Enum for window event types.
Definition IWindow.hpp:45
KeyCode
Definition Keyboard.hpp:23
MouseButton
Definition Mouse.hpp:14
Struct for window size.
Definition IWindow.hpp:23
Struct for image.
Definition Image.hpp:20
static cae::KeyCode translateKeysym(const KeySym sym)
Definition x11.cpp:12