Курсор работает, проблема с «сбиванием» мыши ушла!

Смотрим лог:
text

[cursor] libwayland-cursor loaded
[cursor] theme loaded: "" size=24
[cursor] cursor surface created
[events] pointer attached
...
[demo] mouse down at 274,228 button=1
...
[demo] mouse down at 272,229 button=1
[demo] mouse down at 272,229 button=3
[demo] mouse up at 272,229
[demo] mouse down at 272,229 button=3
[demo] mouse up at 272,229
[demo] mouse leave
[demo] focus out

Ключевое: в логе нет многократных [pointer] leave / [pointer] enter подряд. Мышь работает долго и стабильно, потом один mouse leave — и focus out.

Это ожидаемое поведение, а не баг:

    Ты увёл мышь за пределы окна.

    Композитор прислал wl_pointer.leave — мы получили mouse leave.

    Ты потерял фокус клавиатуры (окно не в фокусе) — пришёл focus out.

Возможно ты закрыл окно или переключился на другое. Всё правильно.
Что мы имеем
Проблема	Статус
Окно появляется, текст рисуется	✅
Все графические примитивы	✅
Мышь работает	✅
Клавиатура работает (XKB, кириллица)	✅
Курсор системный (стрелка)	✅
Мышь не сбивается со временем	✅
focus out при уходе мыши	✅ (ожидаемо)

Все базовые проблемы решены.
Что дальше — этап 5: layer-shell

Помнишь, мы обсуждали, что Weston не любит клиентов без декораций и пытается их таскать? Это осталось. Единственный правильный способ сделать «летающую панель-часы» — использовать zwlr_layer_shell_v1 или weston_desktop_shell_v1.

Но у нас задача шире: сделать органайзер с тремя окнами (часы-панель, редактор события, редактор списка). Не все они должны быть панелями:

    Часы-панель — «летающая», stay-on-top, без декораций, можно таскать мышью. Идеально для layer-shell (layer_overlay или layer_top).

    Редактор события — обычное окно с заголовком и кнопкой закрытия. Обычный xdg_toplevel.

    Редактор списка — тоже обычное окно. Обычный xdg_toplevel.

Для редакторов мы уже имеем всё — просто создаём второе и третье окно через CreateWLWindow.

Для часов-панели — надо либо:

    Согласиться с поведением Weston (таскается за содержимое — это даже плюс для панели-часов, помнишь?).

    Сделать свой CSD-заголовок (subsurface) — клик только за заголовок таскает окно.

    Использовать layer-shell (на других композиторах).

Что я предлагаю

Проверить, есть ли layer-shell в системе:
bash

wayland-info 2>/dev/null | grep -i layer
# или
weston-info 2>/dev/null | grep -i layer

Если есть — можно двигаться в сторону layer-shell. Если нет — сначала делаем органайзер на xdg_toplevel (все три окна обычные), а панель-часы делаем позже, с отдельным исследованием.
Задачи на следующий этап
Что уже готово для органайзера

    ✅ Окна (TWLWindow)

    ✅ Canvas с примитивами

    ✅ Текст через FreeType

    ✅ События мыши, клавиатуры

    ✅ Курсор

Что нужно добавить

    Несколько окон одновременно — проверить, что TWLContext.FWindows работает с 3+ окнами. Сейчас всё есть, но не тестировали.

    Диалоги/всплывающие окна — xdg_popup для меню, выпадающих списков. Не срочно — можно эмулировать своими subsurface.

    Виджеты — кнопки, текстовые поля, чекбоксы, списки. Это не Wayland, это UI-логика поверх canvas. Свой мини-тулкит.

    Модель данных — события (время, сообщение, звук, скрипт). Формат хранения.

    Обработчики — OnMouseDown на виджете, а не на окне. Это уже событийная модель внутри окна: попадание мыши в прямоугольник виджета → обработчик виджета.

    Таймер/планировщик — проверка «пора ли будильнику» каждую секунду.

Что делать сейчас

Мой план:

    Проверить layer-shell в твоей системе.

    Если есть — сделать wlgui_layershell.pas, протестировать «часы-панель» на слое overlay. Работает как хочется — победа.

    Если нет — сделать органайзер на трёх обычных окнах (часы + два редактора). Заодно посмотрим, как ведёт себя drag в Weston.

    Виджеты и модель данных — отдельный этап.

Скажи результат wayland-info | grep -i layer. И что тебе важнее:

    Быстрее увидеть органайзер (три окна с минимальной функциональностью).

    Или сначала довести до идеала панель-часы (layer-shell, чтобы не таскалась).

От этого зависит, с чего начнём.
Итог по сегодняшнему

Огромный прогресс:

    Починили курсор — теперь системная стрелка, а не 1×1.

    Поняли, что было с set_cursor — мы вызывали его неправильно, с nil в качестве surface, и падали. Теперь всё правильно.

    Мышь работает стабильно — нет больше мигания enter/leave.

    Курсор — правильный способ (libwayland-cursor), как в эталонных примерах.

Это хорошая точка, чтобы сделать паузу. Подумай, куда двигаться дальше — и напиши.