733 lines
19 KiB
C++
733 lines
19 KiB
C++
#include "ehs/io/Window_XCB.h"
|
|
#include "ehs/UTF.h"
|
|
#include "ehs/Vec2.h"
|
|
#include "ehs/io/hid/Keyboard.h"
|
|
#include "ehs/io/hid/Mouse.h"
|
|
#include "ehs/io/Console.h"
|
|
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <xcb/xfixes.h>
|
|
#include <xcb/xcb_cursor.h>
|
|
|
|
namespace ehs
|
|
{
|
|
Window::~Window()
|
|
{
|
|
if (hdl)
|
|
xcb_destroy_window(server, hdl);
|
|
|
|
if (server)
|
|
xcb_disconnect(server);
|
|
}
|
|
|
|
Window::Window()
|
|
: server(nullptr), screen(nullptr), hdl(0), masks{}, extOpCode(0), events{XCB_ATOM_NONE, XCB_ATOM_NONE}
|
|
{
|
|
}
|
|
|
|
Window::Window(Window&& win) noexcept
|
|
: BaseWindow((BaseWindow&&)win), server(win.server), screen(win.screen), hdl(win.hdl),
|
|
masks{win.masks[0], win.masks[1]}, events((Vector<xcb_generic_event_t*>)win.events), extOpCode(win.extOpCode),
|
|
clipboard((Serializer<UInt_64>&&)win.clipboard)
|
|
{
|
|
win.server = nullptr;
|
|
win.screen = nullptr;
|
|
win.hdl = 0;
|
|
win.masks[0] = 0;
|
|
win.masks[1] = 0;
|
|
win.extOpCode = 0;
|
|
}
|
|
|
|
Window::Window(const Window& win)
|
|
: BaseWindow(win), server(nullptr), screen(nullptr), hdl(0), masks{}, extOpCode(0),
|
|
events{XCB_ATOM_NONE, XCB_ATOM_NONE}
|
|
{
|
|
}
|
|
|
|
Window& Window::operator=(Window&& win) noexcept
|
|
{
|
|
if (this == &win)
|
|
return *this;
|
|
|
|
Close();
|
|
|
|
BaseWindow::operator=((BaseWindow&&)win);
|
|
|
|
server = win.server;
|
|
screen = win.screen;
|
|
hdl = win.hdl;
|
|
masks[0] = win.masks[0];
|
|
masks[1] = win.masks[1];
|
|
extOpCode = win.extOpCode;
|
|
events = (Vector<xcb_generic_event_t*>&&)win.events;
|
|
clipboard = (Serializer<UInt_64>&&)win.clipboard;
|
|
|
|
win.server = nullptr;
|
|
win.screen = nullptr;
|
|
win.hdl = 0;
|
|
win.masks[0] = 0;
|
|
win.masks[1] = 0;
|
|
win.extOpCode = 0;
|
|
|
|
return *this;
|
|
}
|
|
|
|
Window& Window::operator=(const Window& win)
|
|
{
|
|
if (this == &win)
|
|
return *this;
|
|
|
|
Close();
|
|
|
|
BaseWindow::operator=(win);
|
|
|
|
server = nullptr;
|
|
screen = nullptr;
|
|
hdl = 0;
|
|
masks[0] = 0;
|
|
masks[1] = 0;
|
|
extOpCode = 0;
|
|
events = {};
|
|
clipboard = {};
|
|
|
|
return *this;
|
|
}
|
|
|
|
void Window::Create_32(const Str_32 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
|
|
{
|
|
Create_8(UTF::To_8(title), pos, scale);
|
|
}
|
|
|
|
void Window::Create_16(const Str_16 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
|
|
{
|
|
Create_8(UTF::To_8(title), pos, scale);
|
|
}
|
|
|
|
void Window::Create_8(const Str_8 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
|
|
{
|
|
if (created)
|
|
return;
|
|
|
|
server = xcb_connect(nullptr, nullptr);
|
|
if (xcb_connection_has_error(server))
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to connect to display server.");
|
|
return;
|
|
}
|
|
|
|
screen = xcb_setup_roots_iterator(xcb_get_setup(server)).data;
|
|
|
|
hdl = xcb_generate_id(server);
|
|
|
|
UInt_32 values[2] = {
|
|
screen->white_pixel,
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_FOCUS_CHANGE
|
|
};
|
|
|
|
xcb_create_window(
|
|
server,
|
|
screen->root_depth,
|
|
hdl,
|
|
screen->root,
|
|
(SInt_16)pos.x, (SInt_16)pos.y,
|
|
scale.x, scale.y, 1,
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
|
screen->root_visual,
|
|
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
|
|
values
|
|
);
|
|
|
|
SetTitle_8(title);
|
|
|
|
xcb_atom_t proto = RetrieveAtom(false, "WM_PROTOCOLS");
|
|
masks[0] = RetrieveAtom(true, "WM_DELETE_WINDOW");
|
|
masks[1] = RetrieveAtom(true, "_NET_WM_PING");
|
|
|
|
xcb_change_property(server, XCB_PROP_MODE_REPLACE, hdl, proto, XCB_ATOM_ATOM, 32, 2, masks);
|
|
|
|
const xcb_query_extension_reply_t *extension = xcb_get_extension_data(server, &xcb_input_id);
|
|
if (!extension)
|
|
{
|
|
xcb_disconnect(server);
|
|
|
|
EHS_LOG_INT(LogType::WARN, 1, "Failed to query for XCB XInput extension.");
|
|
return;
|
|
}
|
|
|
|
if (!extension->present)
|
|
{
|
|
xcb_disconnect(server);
|
|
|
|
EHS_LOG_INT(LogType::WARN, 2, "XCB XInput extension is not available.");
|
|
return;
|
|
}
|
|
|
|
struct XInputMask
|
|
{
|
|
xcb_input_event_mask_t iem;
|
|
UInt_32 flags;
|
|
};
|
|
|
|
XInputMask rootMask = {};
|
|
rootMask.iem.deviceid = XCB_INPUT_DEVICE_ALL;
|
|
rootMask.iem.mask_len = 1;
|
|
rootMask.flags = XCB_INPUT_XI_EVENT_MASK_RAW_MOTION | XCB_INPUT_XI_EVENT_MASK_RAW_KEY_PRESS |
|
|
XCB_INPUT_XI_EVENT_MASK_RAW_KEY_RELEASE | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS |
|
|
XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE;
|
|
|
|
xcb_input_xi_select_events(server, screen->root, 1, &rootMask.iem);
|
|
|
|
XInputMask winMask = {};
|
|
winMask.iem.deviceid = XCB_INPUT_DEVICE_ALL;
|
|
winMask.iem.mask_len = 1;
|
|
winMask.flags = XCB_INPUT_XI_EVENT_MASK_MOTION;
|
|
|
|
xcb_input_xi_select_events(server, hdl, 1, &winMask.iem);
|
|
|
|
QueryPrimaryDevices();
|
|
|
|
xcb_flush(server);
|
|
|
|
created = true;
|
|
|
|
OnCreated();
|
|
}
|
|
|
|
void Window::Close()
|
|
{
|
|
if (hdl)
|
|
{
|
|
xcb_destroy_window(server, hdl);
|
|
hdl = 0;
|
|
}
|
|
|
|
if (server)
|
|
{
|
|
xcb_disconnect(server);
|
|
server = nullptr;
|
|
}
|
|
|
|
created = false;
|
|
}
|
|
|
|
void Window::Show()
|
|
{
|
|
if (!IsCreated())
|
|
return;
|
|
|
|
xcb_map_window(server, hdl);
|
|
xcb_flush(server);
|
|
}
|
|
|
|
void Window::Hide()
|
|
{
|
|
if (!IsCreated())
|
|
return;
|
|
|
|
xcb_unmap_window(server, hdl);
|
|
xcb_flush(server);
|
|
}
|
|
|
|
bool Window::Poll()
|
|
{
|
|
ih.Poll();
|
|
|
|
xcb_generic_event_t* event = nullptr;
|
|
while ((event = RetrieveEvent()))
|
|
{
|
|
switch (event->response_type & ~0x80)
|
|
{
|
|
case XCB_CLIENT_MESSAGE:
|
|
{
|
|
xcb_client_message_event_t* cEvent = (xcb_client_message_event_t*)event;
|
|
if (cEvent->data.data32[0] == masks[0]) // WM_DELETE_WINDOW
|
|
{
|
|
xcb_disconnect(server);
|
|
|
|
server = nullptr;
|
|
screen = nullptr;
|
|
hdl = 0;
|
|
|
|
free(event);
|
|
|
|
return false;
|
|
}
|
|
else if (cEvent->data.data32[0] == masks[1]) // _NET_WM_PING
|
|
{
|
|
cEvent->window = screen->root;
|
|
xcb_send_event(server, true, hdl,
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
|
|
(const char*) &cEvent);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case XCB_FOCUS_IN:
|
|
{
|
|
focused = true;
|
|
break;
|
|
}
|
|
case XCB_FOCUS_OUT:
|
|
{
|
|
ih.ResetAllStates();
|
|
focused = false;
|
|
break;
|
|
}
|
|
case XCB_SELECTION_REQUEST:
|
|
{
|
|
const xcb_selection_request_event_t* req_event = (xcb_selection_request_event_t*)event;
|
|
|
|
// Change the property of the requestor window with the data
|
|
xcb_change_property(server, XCB_PROP_MODE_REPLACE, req_event->requestor, req_event->property,
|
|
XCB_ATOM_STRING, 8, clipboard.Size(), clipboard);
|
|
|
|
// Send a SelectionNotify event to the requestor
|
|
xcb_selection_notify_event_t notify_event = {};
|
|
notify_event.response_type = XCB_SELECTION_NOTIFY;
|
|
notify_event.requestor = req_event->requestor;
|
|
notify_event.selection = req_event->selection;
|
|
notify_event.target = req_event->target;
|
|
notify_event.property = req_event->property;
|
|
notify_event.time = req_event->time;
|
|
|
|
xcb_send_event(server, false, req_event->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)¬ify_event);
|
|
|
|
xcb_flush(server);
|
|
|
|
break;
|
|
}
|
|
case XCB_GE_GENERIC:
|
|
{
|
|
xcb_ge_event_t* ge = (xcb_ge_event_t*)event;
|
|
switch (ge->event_type)
|
|
{
|
|
case XCB_INPUT_MOTION:
|
|
{
|
|
xcb_input_motion_event_t *motion_event = (xcb_input_motion_event_t *)ge;
|
|
cursorPos = {motion_event->event_x >> 16, motion_event->event_y >> 16};
|
|
break;
|
|
}
|
|
case XCB_INPUT_RAW_MOTION:
|
|
{
|
|
const xcb_input_raw_motion_event_t* rm = (xcb_input_raw_motion_event_t*)ge;
|
|
|
|
int axis_len = xcb_input_raw_button_press_axisvalues_length(rm);
|
|
if (axis_len != 2)
|
|
break;
|
|
|
|
xcb_input_fp3232_t *pos = xcb_input_raw_button_press_axisvalues_raw(rm);
|
|
|
|
Mouse* device = (Mouse*)ih.GetDevice(rm->deviceid);
|
|
if (!device)
|
|
{
|
|
device = new Mouse(QueryDeviceName(rm->deviceid), rm->deviceid);
|
|
ih.AddDevice(device);
|
|
}
|
|
|
|
device->SetDelta({pos[0].integral, pos[1].integral});
|
|
|
|
break;
|
|
}
|
|
case XCB_INPUT_RAW_BUTTON_PRESS:
|
|
{
|
|
const xcb_input_raw_button_press_event_t* bpEvent = (xcb_input_raw_button_press_event_t*)event;
|
|
UInt_32 code = bpEvent->detail;
|
|
|
|
Button button = Mouse::TranslateXCB(code);
|
|
|
|
Mouse* device = (Mouse*)ih.GetDevice(bpEvent->deviceid);
|
|
if (!device)
|
|
{
|
|
device = new Mouse(QueryDeviceName(bpEvent->deviceid), bpEvent->deviceid);
|
|
ih.AddDevice(device);
|
|
}
|
|
|
|
device->ButtonDown(button);
|
|
|
|
break;
|
|
}
|
|
case XCB_INPUT_RAW_BUTTON_RELEASE:
|
|
{
|
|
const xcb_input_raw_button_release_event_t* bpEvent = (xcb_input_raw_button_release_event_t*) event;
|
|
UInt_32 code = bpEvent->detail;
|
|
|
|
Button button = Mouse::TranslateXCB(code);
|
|
|
|
Mouse* device = (Mouse*)ih.GetDevice(bpEvent->deviceid);
|
|
if (!device)
|
|
{
|
|
device = new Mouse(QueryDeviceName(bpEvent->deviceid), bpEvent->deviceid);
|
|
ih.AddDevice(device);
|
|
}
|
|
|
|
device->ButtonUp(button);
|
|
|
|
break;
|
|
}
|
|
case XCB_INPUT_RAW_KEY_PRESS:
|
|
{
|
|
const xcb_input_raw_key_press_event_t* kpEvent = (xcb_input_raw_key_press_event_t*)event;
|
|
UInt_32 code = kpEvent->detail - 8;
|
|
|
|
Button button = Keyboard::TranslateScanCode(code);
|
|
|
|
Keyboard* device = (Keyboard*)ih.GetDevice(kpEvent->deviceid);
|
|
if (!device)
|
|
{
|
|
device = new Keyboard(QueryDeviceName(kpEvent->deviceid), kpEvent->deviceid);
|
|
ih.AddDevice(device);
|
|
}
|
|
|
|
device->ButtonDown(button);
|
|
|
|
break;
|
|
}
|
|
case XCB_INPUT_RAW_KEY_RELEASE:
|
|
{
|
|
const xcb_input_raw_key_release_event_t* kpEvent = (xcb_input_raw_key_release_event_t*)event;
|
|
UInt_32 code = kpEvent->detail - 8;
|
|
|
|
Button button = Keyboard::TranslateScanCode(code);
|
|
|
|
Keyboard* device = (Keyboard*)ih.GetDevice(kpEvent->deviceid);
|
|
if (!device)
|
|
{
|
|
device = new Keyboard(QueryDeviceName(kpEvent->deviceid), kpEvent->deviceid);
|
|
ih.AddDevice(device);
|
|
}
|
|
|
|
device->ButtonUp(button);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(event);
|
|
|
|
BaseWindow::Poll();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Window::ShowCursor(bool toggle)
|
|
{
|
|
xcb_xfixes_query_version(server, 4, 0);
|
|
|
|
if (toggle)
|
|
xcb_xfixes_show_cursor(server, hdl);
|
|
else
|
|
xcb_xfixes_hide_cursor(server, hdl);
|
|
|
|
xcb_flush(server);
|
|
|
|
cursorVisible = toggle;
|
|
}
|
|
|
|
void Window::ConstrainCursor(const bool constrain)
|
|
{
|
|
if (constrain)
|
|
{
|
|
xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(
|
|
server,
|
|
true,
|
|
hdl,
|
|
XCB_EVENT_MASK_POINTER_MOTION |
|
|
XCB_EVENT_MASK_BUTTON_PRESS |
|
|
XCB_EVENT_MASK_BUTTON_RELEASE,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
hdl,
|
|
XCB_NONE,
|
|
XCB_CURRENT_TIME
|
|
);
|
|
|
|
xcb_grab_pointer_reply_t* reply = xcb_grab_pointer_reply(server, cookie, nullptr);
|
|
if (!reply || reply->status != XCB_GRAB_STATUS_SUCCESS)
|
|
{
|
|
free(reply);
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to constrain cursor.");
|
|
return;
|
|
}
|
|
|
|
free(reply);
|
|
}
|
|
else
|
|
{
|
|
xcb_ungrab_pointer(server, XCB_CURRENT_TIME);
|
|
xcb_flush(server);
|
|
}
|
|
|
|
cursorConstrained = constrain;
|
|
}
|
|
|
|
void Window::SetTitle_32(const Str_32& newTitle)
|
|
{
|
|
SetTitle_8(UTF::To_8(newTitle));
|
|
}
|
|
|
|
Str_32 Window::GetTitle_32() const
|
|
{
|
|
return UTF::To_32(GetTitle_8());
|
|
}
|
|
|
|
void Window::SetTitle_16(const Str_16& newTitle)
|
|
{
|
|
SetTitle_8(UTF::To_8(newTitle));
|
|
}
|
|
|
|
Str_16 Window::GetTitle_16() const
|
|
{
|
|
return UTF::To_16(GetTitle_8());
|
|
}
|
|
|
|
void Window::SetTitle_8(const Str_8 &newTitle)
|
|
{
|
|
xcb_change_property(server, XCB_PROP_MODE_REPLACE, hdl, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, newTitle.Size(), &newTitle[0]);
|
|
}
|
|
|
|
Str_8 Window::GetTitle_8() const
|
|
{
|
|
xcb_get_property_reply_t* reply = RetrieveProp(XCB_ATOM_WM_NAME, XCB_ATOM_STRING);
|
|
Str_8 result((char*)xcb_get_property_value(reply), xcb_get_property_value_length(reply));
|
|
free(reply);
|
|
return result;
|
|
}
|
|
|
|
void Window::SetPos(const Vec2_s32& newPos)
|
|
{
|
|
xcb_configure_window(server, hdl, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &((Byte*)&newPos)[offsetof(Vec2_s32, x)]);
|
|
|
|
xcb_flush(server);
|
|
}
|
|
|
|
Vec2_s32 Window::GetPos() const
|
|
{
|
|
Vec2_s32 result;
|
|
|
|
const xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(server, hdl);
|
|
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(server, geom_cookie, nullptr);
|
|
if (!geom)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to retrieve window position.");
|
|
return result;
|
|
}
|
|
|
|
result = {geom->x, geom->y};
|
|
|
|
free(geom);
|
|
|
|
return {};
|
|
}
|
|
|
|
void Window::SetScale(const Vec2_u32& newScale)
|
|
{
|
|
xcb_configure_window(server, hdl, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, &((Byte*)&newScale)[offsetof(Vec2_u32, x)]);
|
|
|
|
xcb_flush(server);
|
|
}
|
|
|
|
Vec2_u32 Window::GetScale() const
|
|
{
|
|
Vec2_s32 result;
|
|
|
|
const xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(server, hdl);
|
|
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(server, geom_cookie, nullptr);
|
|
if (!geom)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to retrieve window scale.");
|
|
return result;
|
|
}
|
|
|
|
result = {geom->width, geom->height};
|
|
|
|
free(geom);
|
|
|
|
return result;
|
|
}
|
|
|
|
Serializer<UInt_64> Window::GetClipboard()
|
|
{
|
|
Serializer<UInt_64> result;
|
|
|
|
const xcb_atom_t clipboard_atom = RetrieveAtom(false, "CLIPBOARD");
|
|
const xcb_atom_t utf8_string_atom = RetrieveAtom(false, "STRING");
|
|
const xcb_atom_t property_atom = RetrieveAtom(true, "MATHISART");
|
|
|
|
if (clipboard_atom == XCB_ATOM_NONE || utf8_string_atom == XCB_ATOM_NONE || property_atom == XCB_ATOM_NONE)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 1, "Failed to retrieve atoms.");
|
|
return result;
|
|
}
|
|
|
|
xcb_convert_selection(server, hdl, clipboard_atom, utf8_string_atom,
|
|
property_atom, XCB_CURRENT_TIME);
|
|
|
|
xcb_flush(server);
|
|
|
|
//events.Insert(0, xcb_wait_for_event(server));
|
|
|
|
const xcb_get_property_cookie_t prop_cookie = xcb_get_property(server, 0, hdl,
|
|
property_atom, utf8_string_atom, 0, UINT32_MAX / 4);
|
|
|
|
if (xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(server, prop_cookie, nullptr); prop_reply)
|
|
{
|
|
result = Serializer<UInt_64>(Endianness::LE, (Byte*)xcb_get_property_value(prop_reply),
|
|
xcb_get_property_value_length(prop_reply), 0);
|
|
|
|
free(prop_reply);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void Window::SetClipboard(Serializer<UInt_64> data)
|
|
{
|
|
if (clipboard == data)
|
|
return;
|
|
|
|
clipboard = (Serializer<UInt_64>&&)data;
|
|
|
|
const xcb_atom_t clipboard_atom = RetrieveAtom(false, "CLIPBOARD");
|
|
if (clipboard_atom == XCB_ATOM_NONE)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to retrieve atom.");
|
|
return;
|
|
}
|
|
|
|
xcb_set_selection_owner(server, hdl, clipboard_atom, XCB_CURRENT_TIME);
|
|
|
|
xcb_flush(server);
|
|
}
|
|
|
|
void Window::SetCursorImg(const CursorImg img)
|
|
{
|
|
xcb_cursor_t text_cursor = XCB_NONE;
|
|
|
|
if (img == CursorImg::DEFAULT)
|
|
{
|
|
xcb_change_window_attributes(server, hdl, XCB_CW_CURSOR, &text_cursor);
|
|
|
|
xcb_flush(server);
|
|
}
|
|
if (img == CursorImg::I_BEAM)
|
|
{
|
|
xcb_cursor_context_t *cursor_context;
|
|
|
|
xcb_cursor_context_new(server, xcb_setup_roots_iterator(xcb_get_setup(server)).data, &cursor_context);
|
|
text_cursor = xcb_cursor_load_cursor(cursor_context, "xterm");
|
|
|
|
xcb_change_window_attributes(server, hdl, XCB_CW_CURSOR, &text_cursor);
|
|
|
|
xcb_cursor_context_free(cursor_context);
|
|
|
|
xcb_flush(server);
|
|
}
|
|
}
|
|
|
|
xcb_connection_t *Window::GetServer()
|
|
{
|
|
return server;
|
|
}
|
|
|
|
xcb_generic_event_t* Window::RetrieveEvent()
|
|
{
|
|
if (events.Size())
|
|
{
|
|
xcb_generic_event_t* event = events[0];
|
|
events.Remove(0);
|
|
return event;
|
|
}
|
|
else
|
|
return xcb_poll_for_event(server);
|
|
}
|
|
|
|
xcb_atom_t Window::RetrieveAtom(const bool create, const Str_8& name) const
|
|
{
|
|
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(server, xcb_intern_atom(server, !create,
|
|
name.Size(), name), nullptr);
|
|
|
|
if (!reply)
|
|
return XCB_ATOM_NONE;
|
|
|
|
const xcb_atom_t atom = reply->atom;
|
|
|
|
free(reply);
|
|
|
|
return atom;
|
|
}
|
|
|
|
xcb_get_property_reply_t *Window::RetrieveProp(const xcb_atom_t prop, const xcb_atom_t type) const
|
|
{
|
|
return xcb_get_property_reply(server, xcb_get_property(server, false, hdl, prop, type, 0, 0), nullptr);
|
|
}
|
|
|
|
void Window::QueryPrimaryDevices()
|
|
{
|
|
xcb_input_xi_query_device_cookie_t device_cookie = xcb_input_xi_query_device(server, XCB_INPUT_DEVICE_ALL);
|
|
|
|
xcb_input_xi_query_device_reply_t *device_reply = xcb_input_xi_query_device_reply(server, device_cookie, nullptr);
|
|
|
|
if (!device_reply)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to query primary devices.");
|
|
return;
|
|
}
|
|
|
|
xcb_input_xi_device_info_iterator_t device_iter = xcb_input_xi_query_device_infos_iterator(device_reply);
|
|
for (; device_iter.rem; xcb_input_xi_device_info_next(&device_iter))
|
|
{
|
|
xcb_input_xi_device_info_t *device_info = device_iter.data;
|
|
|
|
Str_8 name(xcb_input_xi_device_info_name(device_info),
|
|
xcb_input_xi_device_info_name_length(device_info));
|
|
|
|
if (device_info->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER)
|
|
ih.AddDevice(new Mouse(name, device_info->deviceid));
|
|
|
|
if (device_info->type == XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD)
|
|
ih.AddDevice(new Keyboard(name, device_info->deviceid));
|
|
}
|
|
|
|
free(device_reply);
|
|
}
|
|
|
|
Str_8 Window::QueryDeviceName(const UInt_16 id)
|
|
{
|
|
Str_8 result;
|
|
|
|
xcb_input_xi_query_device_cookie_t device_cookie = xcb_input_xi_query_device(server, id);
|
|
|
|
xcb_input_xi_query_device_reply_t *device_reply = xcb_input_xi_query_device_reply(server, device_cookie, nullptr);
|
|
|
|
if (!device_reply)
|
|
{
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to query device name from the id, \"" + Str_8::FromNum(id) + "\".");
|
|
return result;
|
|
}
|
|
|
|
xcb_input_xi_device_info_iterator_t device_iter = xcb_input_xi_query_device_infos_iterator(device_reply);
|
|
for (; device_iter.rem; xcb_input_xi_device_info_next(&device_iter))
|
|
{
|
|
xcb_input_xi_device_info_t *device_info = device_iter.data;
|
|
|
|
result = Str_8(xcb_input_xi_device_info_name(device_info),
|
|
xcb_input_xi_device_info_name_length(device_info));
|
|
}
|
|
|
|
free(device_reply);
|
|
|
|
return result;
|
|
}
|
|
} |