fix(wayland): constant-initialised statics in Device, for clang 23.1 on aarch64-musl
With the touch positions in an inline static std::unordered_map and the text input's strings in inline static std::strings, clang 23.1 crashed compiling Device.cpp for aarch64-alpine-linux-musl against that sysroot's libc++ 22 — in LazyCallGraph at -O3, in the ThinLTO bitcode writer at -O0 (a dangling global); the native build was fine. The fingers now live in a constant-initialised array of slots and the strings in function-local statics of the implementation unit; nothing else changes.
This commit is contained in:
parent
0d8287c122
commit
cc04d4e121
3 changed files with 80 additions and 23 deletions
|
|
@ -338,6 +338,44 @@ void Device::handle_global(void *data, wl_registry *registry, std::uint32_t name
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A finger's slot by id, or a free one for a new finger; nullptr with more
|
||||
// than ten fingers down.
|
||||
Crafter::Device::TouchSlot* SlotFor(std::int32_t id) {
|
||||
Crafter::Device::TouchSlot* free = nullptr;
|
||||
for (Crafter::Device::TouchSlot& slot : Crafter::Device::touchSlots) {
|
||||
if (slot.used && slot.id == id) return &slot;
|
||||
if (!slot.used && free == nullptr) free = &slot;
|
||||
}
|
||||
if (free != nullptr) {
|
||||
free->used = true;
|
||||
free->id = id;
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
bool AnyTouch() {
|
||||
for (const Crafter::Device::TouchSlot& slot : Crafter::Device::touchSlots) {
|
||||
if (slot.used) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The text input's pending strings live here, as function-local statics:
|
||||
// an inline static std::string in the interface made clang 23.1 crash
|
||||
// in ThinLTO for aarch64-alpine-linux-musl.
|
||||
struct TextInputStrings {
|
||||
std::string preedit;
|
||||
std::string shown; // what the window was last told
|
||||
std::string commit;
|
||||
};
|
||||
|
||||
TextInputStrings& TextStrings() {
|
||||
static TextInputStrings strings;
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
void Device::text_input_enter(void*, zwp_text_input_v3*, wl_surface* surface) {
|
||||
textInputWindow = nullptr;
|
||||
for (Window* window : windows) {
|
||||
|
|
@ -349,17 +387,17 @@ void Device::text_input_enter(void*, zwp_text_input_v3*, wl_surface* surface) {
|
|||
void Device::text_input_leave(void*, zwp_text_input_v3*, wl_surface*) {
|
||||
textInputWindow = nullptr;
|
||||
textInputHasPreedit = textInputHasCommit = textInputHasDelete = false;
|
||||
textInputPreedit.clear();
|
||||
textInputShownPreedit.clear();
|
||||
TextStrings().preedit.clear();
|
||||
TextStrings().shown.clear();
|
||||
}
|
||||
|
||||
void Device::text_input_preedit(void*, zwp_text_input_v3*, const char* text, std::int32_t, std::int32_t) {
|
||||
textInputPreedit = text == nullptr ? "" : text;
|
||||
TextStrings().preedit = text == nullptr ? "" : text;
|
||||
textInputHasPreedit = true;
|
||||
}
|
||||
|
||||
void Device::text_input_commit(void*, zwp_text_input_v3*, const char* text) {
|
||||
textInputCommit = text == nullptr ? "" : text;
|
||||
TextStrings().commit = text == nullptr ? "" : text;
|
||||
textInputHasCommit = true;
|
||||
}
|
||||
|
||||
|
|
@ -375,17 +413,18 @@ void Device::text_input_delete(void*, zwp_text_input_v3*, std::uint32_t before,
|
|||
// the window hears about it only when that differs from what it shows.
|
||||
void Device::text_input_done(void*, zwp_text_input_v3*, std::uint32_t) {
|
||||
Window* window = textInputWindow;
|
||||
if (!textInputHasPreedit) textInputPreedit.clear();
|
||||
TextInputStrings& strings = TextStrings();
|
||||
if (!textInputHasPreedit) strings.preedit.clear();
|
||||
if (window != nullptr) {
|
||||
if (textInputHasDelete && (textInputDeleteBefore > 0 || textInputDeleteAfter > 0)) window->onTextInputDelete.Invoke({ textInputDeleteBefore, textInputDeleteAfter });
|
||||
if (textInputHasCommit && !textInputCommit.empty()) window->onTextInput.Invoke(textInputCommit);
|
||||
if (textInputPreedit != textInputShownPreedit || (textInputHasCommit && !textInputCommit.empty())) {
|
||||
textInputShownPreedit = textInputPreedit;
|
||||
window->onPreedit.Invoke(textInputPreedit);
|
||||
if (textInputHasCommit && !strings.commit.empty()) window->onTextInput.Invoke(strings.commit);
|
||||
if (strings.preedit != strings.shown || (textInputHasCommit && !strings.commit.empty())) {
|
||||
strings.shown = strings.preedit;
|
||||
window->onPreedit.Invoke(strings.preedit);
|
||||
}
|
||||
}
|
||||
textInputHasPreedit = textInputHasCommit = textInputHasDelete = false;
|
||||
textInputCommit.clear();
|
||||
strings.commit.clear();
|
||||
}
|
||||
|
||||
void Device::ApplyTextInput(Window* window) {
|
||||
|
|
@ -626,6 +665,10 @@ void Device::TickKeyRepeats() {
|
|||
}
|
||||
}
|
||||
|
||||
void Device::ForgetTouches() {
|
||||
for (TouchSlot& slot : touchSlots) slot = TouchSlot{};
|
||||
}
|
||||
|
||||
// The first finger stands in for the pointer: it enters the window (so the
|
||||
// clipboard has a serial and Device::focusedWindow a window), presses the
|
||||
// left button, moves it and releases it. Every finger is also reported as
|
||||
|
|
@ -639,7 +682,10 @@ void Device::touch_down(void*, wl_touch*, std::uint32_t serial, std::uint32_t, w
|
|||
touchWindow = window;
|
||||
window->lastPointerSerial_ = serial;
|
||||
const Vector<float, 2> pos = Vector<float, 2>(wl_fixed_to_double(x), wl_fixed_to_double(y)) * window->scale;
|
||||
touchPositions[id] = { pos.x, pos.y };
|
||||
if (TouchSlot* slot = SlotFor(id)) {
|
||||
slot->x = pos.x;
|
||||
slot->y = pos.y;
|
||||
}
|
||||
window->onTouchDown.Invoke({ id, pos });
|
||||
if (window->primaryTouchId < 0) {
|
||||
window->primaryTouchId = id;
|
||||
|
|
@ -653,23 +699,28 @@ void Device::touch_down(void*, wl_touch*, std::uint32_t serial, std::uint32_t, w
|
|||
void Device::touch_up(void*, wl_touch*, std::uint32_t, std::uint32_t, std::int32_t id) {
|
||||
if (touchWindow == nullptr) return;
|
||||
Window* window = touchWindow;
|
||||
const auto at = touchPositions.find(id);
|
||||
const Vector<float, 2> pos = at == touchPositions.end() ? window->currentMousePos : Vector<float, 2>(at->second.first, at->second.second);
|
||||
touchPositions.erase(id);
|
||||
Vector<float, 2> pos = window->currentMousePos;
|
||||
if (TouchSlot* slot = SlotFor(id)) {
|
||||
pos = Vector<float, 2>(slot->x, slot->y);
|
||||
*slot = TouchSlot{};
|
||||
}
|
||||
window->onTouchUp.Invoke({ id, pos });
|
||||
if (id == window->primaryTouchId) {
|
||||
window->primaryTouchId = -1;
|
||||
window->mouseLeftHeld = false;
|
||||
window->onMouseLeftRelease.Invoke();
|
||||
}
|
||||
if (touchPositions.empty()) touchWindow = nullptr;
|
||||
if (!AnyTouch()) touchWindow = nullptr;
|
||||
}
|
||||
|
||||
void Device::touch_motion(void*, wl_touch*, std::uint32_t, std::int32_t id, wl_fixed_t x, wl_fixed_t y) {
|
||||
if (touchWindow == nullptr) return;
|
||||
Window* window = touchWindow;
|
||||
const Vector<float, 2> pos = Vector<float, 2>(wl_fixed_to_double(x), wl_fixed_to_double(y)) * window->scale;
|
||||
touchPositions[id] = { pos.x, pos.y };
|
||||
if (TouchSlot* slot = SlotFor(id)) {
|
||||
slot->x = pos.x;
|
||||
slot->y = pos.y;
|
||||
}
|
||||
window->onTouchMove.Invoke({ id, pos });
|
||||
if (id == window->primaryTouchId) {
|
||||
window->currentMousePos = pos;
|
||||
|
|
@ -682,7 +733,7 @@ void Device::touch_frame(void*, wl_touch*) {}
|
|||
void Device::touch_cancel(void*, wl_touch*) {
|
||||
if (touchWindow == nullptr) return;
|
||||
Window* window = touchWindow;
|
||||
touchPositions.clear();
|
||||
ForgetTouches();
|
||||
touchWindow = nullptr;
|
||||
if (window->primaryTouchId >= 0) {
|
||||
window->primaryTouchId = -1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue