UI rewrite 3rd attempt
This commit is contained in:
parent
c9fd1b1585
commit
1f5697326c
48 changed files with 2155 additions and 6190 deletions
|
|
@ -516,109 +516,113 @@ void Window::SetTitle(const std::string_view title) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void Window::SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY) {
|
||||
void Window::SetCursorImage(std::uint16_t width, std::uint16_t height,
|
||||
std::uint16_t hotspotX, std::uint16_t hotspotY,
|
||||
const std::uint8_t* pixels) {
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
if(cursorSurface == nullptr) {
|
||||
if (width == 0 || height == 0 || pixels == nullptr) {
|
||||
SetDefaultCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursorSurface == nullptr) {
|
||||
cursorSurface = wl_compositor_create_surface(Device::compositor);
|
||||
}
|
||||
|
||||
int stride = width * 4;
|
||||
int size = stride * height;
|
||||
|
||||
// Reuse the existing mmap+buffer if the size is unchanged; otherwise
|
||||
// tear down and re-allocate.
|
||||
if (cursorWlBuffer != nullptr &&
|
||||
cursorBufferOldSize == static_cast<std::uint32_t>(size)) {
|
||||
// size unchanged — keep the buffer and mmap.
|
||||
} else {
|
||||
if (cursorMmap_) {
|
||||
munmap(cursorMmap_, cursorBufferOldSize);
|
||||
cursorMmap_ = nullptr;
|
||||
}
|
||||
if (cursorWlBuffer) {
|
||||
wl_buffer_destroy(cursorWlBuffer);
|
||||
cursorWlBuffer = nullptr;
|
||||
}
|
||||
|
||||
int fd = create_shm_file(size);
|
||||
if (fd < 0) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Window::SetCursorImage: shm allocation for {}B failed", size));
|
||||
}
|
||||
void* mapped = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (mapped == MAP_FAILED) {
|
||||
close(fd);
|
||||
throw std::runtime_error("Window::SetCursorImage: mmap failed");
|
||||
}
|
||||
cursorMmap_ = static_cast<std::uint8_t*>(mapped);
|
||||
|
||||
wl_shm_pool* pool = wl_shm_create_pool(Device::shm, fd, size);
|
||||
cursorWlBuffer = wl_shm_pool_create_buffer(
|
||||
pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(fd);
|
||||
|
||||
cursorBufferOldSize = static_cast<std::uint32_t>(size);
|
||||
}
|
||||
|
||||
// Convert the user's straight-alpha RGBA8 pixels into the compositor's
|
||||
// expected premultiplied BGRA8 (= ARGB8888 little-endian byte order).
|
||||
for (int i = 0; i < width * height; ++i) {
|
||||
std::uint8_t r = pixels[i * 4 + 0];
|
||||
std::uint8_t g = pixels[i * 4 + 1];
|
||||
std::uint8_t b = pixels[i * 4 + 2];
|
||||
std::uint8_t a = pixels[i * 4 + 3];
|
||||
cursorMmap_[i * 4 + 0] = static_cast<std::uint8_t>((b * a) / 255);
|
||||
cursorMmap_[i * 4 + 1] = static_cast<std::uint8_t>((g * a) / 255);
|
||||
cursorMmap_[i * 4 + 2] = static_cast<std::uint8_t>((r * a) / 255);
|
||||
cursorMmap_[i * 4 + 3] = a;
|
||||
}
|
||||
|
||||
cursorHotspotX_ = hotspotX;
|
||||
cursorHotspotY_ = hotspotY;
|
||||
|
||||
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||
wl_surface_damage(cursorSurface, 0, 0, width, height);
|
||||
wl_surface_commit(cursorSurface);
|
||||
|
||||
// If the pointer is currently inside our window, re-apply the cursor
|
||||
// so the new hotspot takes effect immediately. Otherwise the next
|
||||
// pointer-enter event will pick it up.
|
||||
if (Device::wlPointer && Device::focusedWindow == this && lastPointerSerial_) {
|
||||
wl_pointer_set_cursor(Device::wlPointer, lastPointerSerial_,
|
||||
cursorSurface, hotspotX, hotspotY);
|
||||
}
|
||||
#endif
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
||||
// Win32 cursor support is not implemented for the v2 Window.
|
||||
(void)width; (void)height; (void)hotspotX; (void)hotspotY; (void)pixels;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::SetDefaultCursor() {
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
if (cursorMmap_) {
|
||||
munmap(cursorMmap_, cursorBufferOldSize);
|
||||
cursorMmap_ = nullptr;
|
||||
}
|
||||
if (cursorWlBuffer) {
|
||||
wl_buffer_destroy(cursorWlBuffer);
|
||||
cursorWlBuffer = nullptr;
|
||||
}
|
||||
|
||||
int stride = sizeX * 4;
|
||||
int size = stride * sizeY;
|
||||
cursorBufferOldSize = size;
|
||||
|
||||
// Allocate a shared memory file with the right size
|
||||
int fd = create_shm_file(size);
|
||||
if (fd < 0) {
|
||||
throw std::runtime_error(std::format("creating a buffer file for {}B failed", size));
|
||||
}
|
||||
|
||||
wl_shm_pool *pool = wl_shm_create_pool(Device::shm, fd, size);
|
||||
cursorWlBuffer = wl_shm_pool_create_buffer(pool, 0, sizeX, sizeY, stride, WL_SHM_FORMAT_ARGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
close(fd);
|
||||
|
||||
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||
wl_surface_damage(cursorSurface, 0, 0, sizeX, sizeY);
|
||||
wl_surface_commit(cursorSurface);
|
||||
#endif
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
||||
if (cursorBitmap) {
|
||||
DeleteObject(cursorBitmap);
|
||||
if (cursorSurface) {
|
||||
wl_surface_destroy(cursorSurface);
|
||||
cursorSurface = nullptr;
|
||||
}
|
||||
if (cursorHandle) {
|
||||
DestroyCursor(cursorHandle);
|
||||
cursorHandle = nullptr;
|
||||
}
|
||||
|
||||
BITMAPINFO bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = sizeX;
|
||||
bmi.bmiHeader.biHeight = -(int)sizeY; // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
HDC hdc = GetDC(nullptr);
|
||||
cursorBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, reinterpret_cast<void**>(&cursorRenderer.buffer[0]), nullptr, 0);
|
||||
ReleaseDC(nullptr, hdc);
|
||||
|
||||
if (!cursorBitmap) {
|
||||
throw std::runtime_error("CreateDIBSection failed for cursor");
|
||||
}
|
||||
|
||||
cursorSizeX = sizeX;
|
||||
cursorSizeY = sizeY;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::SetCusorImageDefault() {
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
wl_buffer_destroy(cursorWlBuffer);
|
||||
wl_surface_destroy(cursorSurface);
|
||||
cursorSurface = nullptr;
|
||||
#endif
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
||||
if (cursorHandle) {
|
||||
DestroyCursor(cursorHandle);
|
||||
cursorHandle = nullptr;
|
||||
}
|
||||
if (cursorBitmap) {
|
||||
DeleteObject(cursorBitmap);
|
||||
cursorBitmap = nullptr;
|
||||
}
|
||||
// Setting nullptr will make WM_SETCURSOR fall through to the default
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::UpdateCursorImage() {
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||
wl_surface_damage(cursorSurface, 0, 0, 9999999, 99999999);
|
||||
wl_surface_commit(cursorSurface);
|
||||
#endif
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
||||
|
||||
// Create a mask bitmap (all zeros = fully opaque, alpha comes from color bitmap)
|
||||
HBITMAP hMask = CreateBitmap(cursorSizeX, cursorSizeY, 1, 1, nullptr);
|
||||
|
||||
ICONINFO ii = {};
|
||||
ii.fIcon = FALSE;
|
||||
ii.xHotspot = 0;
|
||||
ii.yHotspot = 0;
|
||||
ii.hbmMask = hMask;
|
||||
ii.hbmColor = cursorBitmap;
|
||||
|
||||
if (cursorHandle) {
|
||||
DestroyCursor(cursorHandle);
|
||||
}
|
||||
cursorHandle = (HCURSOR)CreateIconIndirect(&ii);
|
||||
DeleteObject(hMask);
|
||||
|
||||
if (cursorHandle) {
|
||||
SetCursor(cursorHandle);
|
||||
cursorBufferOldSize = 0;
|
||||
cursorHotspotX_ = 0;
|
||||
cursorHotspotY_ = 0;
|
||||
// Tell the compositor to drop our cursor surface — passing nullptr
|
||||
// makes it fall back to the system default.
|
||||
if (Device::wlPointer && Device::focusedWindow == this && lastPointerSerial_) {
|
||||
wl_pointer_set_cursor(Device::wlPointer, lastPointerSerial_, nullptr, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue