Adjusted workflow.
This commit is contained in:
735
src/io/Window_XCB.cpp
Normal file
735
src/io/Window_XCB.cpp
Normal file
@@ -0,0 +1,735 @@
|
||||
#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("Error", 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("Warning", 1, "Failed to query for XCB XInput extension.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!extension->present)
|
||||
{
|
||||
xcb_disconnect(server);
|
||||
|
||||
EHS_LOG_INT("Warning", 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_map_window(server, hdl);
|
||||
|
||||
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("Error", 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("Error", 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("Error", 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("Error", 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("Error", 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("Error", 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("Error", 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user