LINUX.ORG.RU

Сообщения KivApple

 

KDE и разные разрешения экрана

Форум — Desktop

Я использую Arch Linux с KDE5 на своём ноутбуке. Я могу использовать экран ноутбука, а могу подключить большой внешний монитор. При этом я настроил KDE таким образом, что экран ноутбука отключается и внешний монитор становится основным.

Логично, что 12.5 дюймов 1366 х 768 и 25 дюймов 2560 х 1080 удобнее использовать с несколько разными расположениями элементов панели.

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

 ,

KivApple
()

Программно сменить раскладку или узнать о её смене

Форум — Development

Для моей экранной клавиатуры требуется два действия:

1) Повесить какой-то обработчик, который будет вызываться при каждой смене раскладки клавиатуры. При этом окно клавиатуры само по себе никогда не получает фокус. Однако я через XRecord уже отлавливаю все нажатия клавиш (чтобы подсвечивать нажатые клавиши, а также определять изменение режима Caps Lock и Num Lock) и отслеживать глобально ещё какие-то события мне не составит труда.

2) Переключиться на следующую раскладку клавиатуры. То есть действие аналогичное нажатию Ctrl + Shift или какой-либо другой комбинации. Но не с помощью эмуляции соответствующих нажатий, а как-нибудь универсально (ведь вроде как можно иметь несколько раскладок, но не назначить комбинацию их смены и делать всё мышкой через виджет).

Сейчас я делаю это через DBus запросов к org.kde.keyboard и org.kde.KeyboardLayouts, но что-то мне подсказывает, что если запустить мою программу в другом DE, то это всё работать не будет. Хотелось бы более портабельный способ, использующий непосредственно API иксов.

Пробовал глобально ловить события KeymapNotify, но они почему-то не приходят (хотя KeyPress и KeyRelease я получаю, какому бы окну они не адресовались). Также читал, что такая встроенная фича Qt как QEvent::KeyboardLayoutChange не особо то работает.

Что ещё можно попробовать?

 , ,

KivApple
()

QML и масштабирование

Форум — Development

Допустим, есть QQuickWidget, в который загружен QML-объект. Размеры этого виджета могут изменяться (он помещён в Layout и лежит уже в нормальном C++ Qt окне). Хотелось бы, чтобы содержимое при этом масштабировалось. Пробовал вот такое:

QSize baseSize(m_quickWidget.rootObject()->width(), m_quickWidget.rootObject()->height());
float scaleX = (float)m_quickWidget.width() / baseSize.width();
float scaleY = (float)m_quickWidget.height() / baseSize.height();
float scale = qMin(scaleX, scaleY);
m_quickWidget.rootObject()->setScale(scale);

Содержимое виджета масштабируется, но весьма криво - центр трансформации как бы не совпадает с центром объекта, как следствие, он не только меняет ширину и высоту, но и съезжает влево-вверх (по факту его часть выходит за границу QQuickWidget и обрезается). При этом позиция виджета (m_quickWidget.rootObject()->position()) остаётся неизменной, так что вернуть его обратно её обнулением не получится.

Как сделать так, чтобы масштабирование работало нормально?

 ,

KivApple
()

Вопрос по DisplayPort и переходникам

Форум — Linux-hardware

У меня монитор имеет HDMI вход, ноутбук DisplayPort выход. Соединил их через китайский переходник. И заметил следующие особенности:

1) Если воткнуть переходник сначала в DisplayPort, а уже потом подключить к нему HDMI-кабель от монитора, то ноутбук монитор не увидит. Надо обязательно сначала подключить монитор к переходнику, а уже только потом переходник к ноутбуку.

2) Если подключить через переходник спящий монитор, то ноутбук его не видит. И даже если потом разбудить монитор кнопкой (он включится, поищет сигнал какое-то время и опять отключится), то всё равно не увидит. Надо обязательно подключать ноутбук к не спящему монитору (а если он уснул, сначала нажать на кнопку, а уже потом тыкать переходник в ноутбук). При прямом подключении (к другому ноутбуку, у которого есть HDMI порт и переходник не нужен) таких проблем нет - монитор проснётся. Более того, ноутбук видит даже отключенный от розетки монитор в таком случае. Однако, если отправить систему в suspend to disk, а потом пробудить (при этом монитор успеет уснуть), то она нормально увидит монитор при пробуждении, даже если он был подключен через переходник (можно даже за время сна отключить кабель и снова включить, при этом нарушая правило 1).

Вопросы:

1) Я правильно понимаю, что если бы у монитора был DisplayPort-разъём, то никаких бы проблем не было?

2) Всё дело в том, что я взял переходник за 300 рублей, а не за 1000 рублей? Проблемы могут быть решены более качественным переходником? Или это принципиальные проблемы конвертации?

3) Можно ли какие-то из этих проблем решить софтово? Особенно мне не нравится вторая проблема, что надо обязательно жать кнопку на мониторе, причём именно за несколько секунд до втыкания разъёма.

 , ,

KivApple
()

QML и стили

Форум — Development

Вот, допустим, пилю я свою виртуальную клавиатуру, а там у меня собственно сама клавиатура сделана с помощью QML (никогда не работал с ним раньше, но решил, что редактировать раскладки в Qt Creator удобнее, чем вручную высчитывать координаты, а в отличии от QtWidgets можно будет легко добавить загрузку новых раскладок из внешних файлов). Было бы не плохо дать пользователю возможность выбирать один из нескольких стилей оформления.

Как это правильно сделать в случае с QML? В случае с QtWidgets можно было загрузить CSS, в котором можно было бы прописать любые поддерживаемые параметры вида для любого объекта на форме (там ведь можно делать селекторы по именам и по классам объектов).

Я с одной стороны не хотел бы ограничивать возможности стайлинга (типа позволить менять только цвет фона и цвет текста, нет - пусть меняются все доступные атрибуты), а с другой стороны не хочу изобрать велосипед (не писать же свой парсер CSS в самом деле). Какое решение было бы наиболее правильным для Qt Quick интерфейса? Суть в том, чтобы можно было заменить 1 файлик и оформление могло полностью измениться, но при этом остался бы прежним набор и логика элементов.

 ,

KivApple
()

2K монитор и ThinkPad

Форум — Desktop

Сегодня мне пришёл из Китая переходник DisplayPort -> HDMI. Воткнул я его значит одним концом в ThinkPad x230t, а другим концом в свой монитор и... получил разрешение 1920х1080. А должно быть 2560х1080!

Полез в настройки разрешения KDE, а там нету нужного разрешения, максимум Full HD.

Попытался добавить сам:

$ gtf 2560 1080 60

  # 2560x1080 @ 60.00 Hz (GTF) hsync: 67.08 kHz; pclk: 230.76 MHz
  Modeline "2560x1080_60.00"  230.76  2560 2728 3000 3440  1080 1081 1084 1118  -HSync +Vsync

$ xrandr --newmode "2560x1080_60.00" 230.76  2560 2728 3000 3440  1080 1081 1084 1118  -HSync +Vsync
$ xrandr --addmode HDMI1 "2560x1080_60.00"
$ xrandr --output HDMI1 --mode "2560x1080_60.00"
xrandr: Configure crtc 0 failed

Во время выполнения последней команды изображение на мониторе мигает, но остаётся такого же разрешения, как и было.

В чём проблема? Я немного погуглил - сама по себе эта модель ThinkPad должна нормально поддерживать данное разрешение. Так что либо переходник плох (но он же вроде как просто пассивный, не?), либо просто EDID побился из-за переходника (когда я подключал данный монитор к другому ноутбуку по HDMI, то никаких проблем не было, значит монитор всё умеет отдавать), а я не умею его правильно добавлять.

Монитор ничего кроме HDMI не умеет, ThinkPad умеет только VGA и DisplayPort. А поскольку у VGA плохо с поддержкой таких больших разрешений + переходники VGA->HDMI очень дорогие (потому что не бывают пассивными), то DisplayPort->HDMI единственный вариант.

UPD: Вот что может сказать о данном мониторе тот ноутбук, который нормально работает с нужным разрешением: http://pastebin.com/k9AzGJdz

UPD2: Нашёл описание формата modeline, добавил новый режим следующим образом:

$ xrandr --newmode "2560x1080" 185.580 2560 2624 2688 2784 1080 1083 1093 1111 -HSync -VSync
$ xrandr --addmode HDMI1 "2560x1080"
$ xrandr --output HDMI1 --mode "2560x1080"

Монитор успешно переключился на правильное разрешение.

Теперь новая задача: как бы всё это по-корректнее прописать, чтобы не надо было вручную выполнять команды, но при этом дополнительное разрешение появлялось только для этого монитора, а не для всех, которые я подключу к HDMI.

UPD3: Насколько я понимаю, мне нужно создать в /etc/X11/xorg.conf.d файлик с таким содержанием:

Section "Monitor"
        Identifier "Monitor0"
        VendorName "LGD"
        ModelName "???"
        Modeline "2560x1080" 185.580 2560 2624 2688 2784 1080 1083 1093 1111 -HSync -VSync
        Option "PreferredMode" "2560x1080"
EndSection

Но я не понимаю, откуда взять строку, которую нужно поставить вместо ???, а без этой опции правило будет реагировать на любые мониторы от LG, что плохо.

Вот что есть в логе иксов:

[     9.227] (II) intel(0): EDID vendor "LGD", prod id 728

Но как указать prod id в качестве условия для конфига, либо как превратить prod id в ModelName?

UPD4: Ему плевать на кофиг почему-то.

$ cat /etc/X11/xorg.conf.d/99-lg-25um58.conf 
Section "Monitor"
        Identifier "Monitor0"
        VendorName "LGD"
        #ModelName "ULTRAWIDE"
        Modeline "2560x1080" 185.580 2560 2624 2688 2784 1080 1083 1093 1111 -HSync -VSync
        Option "PreferredMode" "2560x1080"
EndSection

Новое разрешение всё равно не добавляется, в логах нет ошибок.

 , , ,

KivApple
()

Qt и глобальный перехват событий иксов

Форум — Development

Я тут работаю над самодельной экранной клавиатурой и для некоторой логики мне требуется следить за всеми нажатиям и отпусканиями клавиш - как виртуальными, так и хардварными. Само моё приложение написано на Qt.

Делаю так:

Display *display = QX11Info::display();
XSelectInput(display, DefaultRootWindow(display), KeyPressMask | KeyReleaseMask);
QApplication::instance()->installNativeEventFilter(this);
...
bool KeyboardWidget::nativeEventFilter(const QByteArray &eventType, void *message, long *) {
	xcb_generic_event_t *ev = static_cast<xcb_generic_event_t*>(message);
	switch (ev->response_type & ~0x80) {
		case XCB_KEY_PRESS: {
			xcb_key_press_event_t *key_press_event = reinterpret_cast<xcb_key_press_event_t*>(ev);
			keyEventReceived(key_press_event->detail, true);
			break;
		}
		case XCB_KEY_RELEASE: {
			xcb_key_release_event_t *key_release_event = reinterpret_cast<xcb_key_release_event_t*>(ev);
			keyEventReceived(key_release_event->detail, false);
			break;
		}
	}
	return false;
}

Пока окно приложения имело фокус, приём клавиатурных событий исправно работал (ещё бы он не работал), но как только я сделал так, чтобы окно фокус не получало (setWindowFlags(Qt::WindowStaysOnTopHint | Qt::ToolTip | Qt::FramelessWindowHint)), всё работать перестало. То есть по факту события глобально не ловятся. Что делать?

 ,

KivApple
()

Kvkbd

Форум — Talks

Использую эту замечательную экранную клавиатуру, одну из немногих (если не единственную), которая приятно выглядит и адекватно работает с разными раскладками. Однако раздражает, что экранная клавиатура появляется на экране каждый раз при входе в систему (она добавлена в автозапуск). Хотелось бы, чтобы она запускалась в скрытом виде, а уже когда потребуется я нажму на её значок в области уведомлений. Однако я не нашёл ни ключей командной строки, ни графических настроек для этого дела.

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

И начинаю я гуглить kvkbd... И вылазят одни ссылки на страницы пакета в разных дистрибутивах, а ещё вот это - http://kde-apps.org/content/show.php/Kvkbd?content=56019. Однако данная ссылка ведёт на несуществующую страницу. В описании пакета в репозитории арча указана эта же битая ссылка. А в качестве исходников PKGBUILD используется http://kde-apps.org/CONTENT/content-files/56019-kvkbd-0.7.2.tar.gz, которая выдаёт 403. То есть даже просто собрать пакет не получится (и да, последний раз он собирался аж в 2015-ом году).

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

А теперь вопросы:

1) Откуда мне взять наиболее актуальную версию исходников этой замечательной софтины?

2) Как правильно её форкнуть? То есть понятное дело, я создаю репозиторий на GitHub и загружаю туда найденные исходники, там же вношу все свои изменения. Но как это сделать правильно с точки зрения лицензии? Могу ли я сохранить оригинальное название и просто добавить себя в список авторов с учётом того, что проект уже больше года признаков жизни не подаёт и даже его официальная веб-страница мертва?

Планирую добавить заветный ключик командной строки, а также портировать на Qt5. Также, если выдастся свободное время и будет настроение, то поизучаю вопрос автопоказа клавиатуры при попадании фокуса в поле ввода (вроде как в Linux есть какой-то интерфейс для этого), разумеется, отключаемое в настройках.

 

KivApple
()

И снова про тачскрины и Linux

Форум — Desktop

Поставил я такой xf86-input-wacom и тачскрин сразу же заработал. Правда, несколько специфически - тап двумя пальцами вызывает контекстное меню, а если двумя пальцами тащить, то будет либо прокрутка, либо зум (зависит от того, меняется ли расстояние между двумя пальцами во время перетаскивания). Это работает не в 100% случаев - зачастую воспринимается как одиночный клик или два клика (сначала по координатам первого пальца, затем по координатам второго пальца). В общем, глючит, но как-то работает. Зато во всех приложениях вообще, даже тех, что тач точно не умеют. Предполагаю, что по факту жесты зума и прокрутки превращаются в события от колёсика мыши (при этом зум делается с помощью эмуляции зажатия клавиши Ctrl).

Затем я поставил пакет kcm-wacomtablet-frameworks-git. Что-то там потыкал и... Google Chrome понял, что у меня есть тачскрин и его появление стало эквивалентно видновому (в хорошем смысле этого слова). Теперь у меня не дискретная, а плавная кинетическая прокрутка, плавный зум, при тапе по тексту появляются специальные штучки для удобного выделения и быстрого доступа к вырезать/вставить/копировать (как на Android прямо). Короче всё круто.

Но... отвалилась эмуляция для остальных приложений. И оказалось, что кроме хрома и плазмы (тач прокрутка нормально работает во всяких менюшках плазмы), ничего тач не умеет. Даже какой-нибудь Dolphin, даже программа настроек плазмы.

Ладно, я могу понять, что не умеет тач какой-нибудь IDLE на Tkinter'е, но Qt5-приложения???

Если поставить галку Enable gestures в модуле настроек, то всё становится по-старому - тач-жесты начинают работать во всех приложениях, но зато приложения, которые явно поддерживают тачскрин перестают понимать, что работают с тачскрином.

В общем, вопрос, что с этим всем делать.

1) Можно как-нибудь сделать так, чтобы для приложений, которые умеют тач всё работало нормально, а для тех, которые не умеют, остался режим эмуляции, который кривой, но зато работает с любым приложением (тут даже винда курит в сторонке - pitch-to-zoom работает в приложении под Wine, которое под офтопиком такое не умело). В крайнем случае какой-нибудь белый список приложений, которым тач-события доходят без обработки.

2) Может есть какой-нибудь модуль или опция, которая позволяет Qt приложениям, которые явно не умеют в тач, использовать эмуляцию?

Поставил пакет для поддержки Wayland в KDE. Выбрал Wayland сессию в дисплейном менеджере. И... в хвалёном Wayland проблемы те же самые что и в иксах - в хроме и плазме тач работает правильно, во всех остальных приложениях не работает ничего кроме простых тапов. Ну а ещё отвалилась авторизация и поэтому NetworkManager не смог подключиться к сети из этой сессии, но думаю эту проблему как раз таки решить можно.

 ,

KivApple
()

Thinkpad и LTE-модем

Форум — Linux-hardware

Хочу заказать соответствующий модуль и вставить в свой новоприобретённый ThinkPad X230T.

Вот что я нашёл: https://ru.aliexpress.com/item/100-New-Original-Sierra-Wireless-AirPrime-EM73...

Для начала смотрим поддерживаемые LTE Band. Нашёл вот такую статью: https://www.iphones.ru/iNotes/556933, там про айфоны, но проблемы те же. Отсюда выясняем, что отечественные операторы используют 7-ой, 20-ый и 38-ой LTE Band. При этом 38-ой только некоторые и только в Москве, так что в крайнем случае можно ими пожертвовать.

Данный модуль поддерживает band'ы с 1 по 5, с 7 по 8, 13-ый, с 17 по 20-ый. То в принципе должен вполне нормально работать по всей России, если только не одновременно отправиться в Москву и не вставить туда симку мегафона или МТС, тогда должен свалиться на 3G. С учётом того, что я за всё время поиска не видел ни одного MiniPCI-E модема, который бы умел 38-ой band, то деваться некуда.

Однако, как известно, у ThinkPad есть белый список беспроводных карточек. Гуглим фразу «EM7345 ThinkPad» и натыкаемся на эту страницу https://support.lenovo.com/ru/ru/documents/pd031021. Видим, что данная карточка и ThinkPad употребляется в одном заголовке на официальном сайте Lenovo. Уже не плохо... Но будет ли оно из коробки работать именно с X230T?

Однако, 5к за карточку отдавать жалко (но при отсутствии альтернатив, я отдам). Быть может, кто-нибудь здесь знает более дешёвые MiniPCI-E 4G модули, совместимые с российским операторами?

И таки что насчёт совместимости с ThinkPad? Есть в нормальном виде полный список модемов, которые совместимы с X230? Тогда бы я просто прогуглил их все, выбрал только те, которые умеют 7 и 20 Band, а затем выбрал из них самый дешёвый.

Или, быть может, я зря беспокоюсь и пропатчить BIOS это не самом деле дело пары часов? Я уже рассматриваю этот вариант и приобрёл прищепку для микросхемы EEPROM, а также программатор на базе CH341 (пофиг на поддержку в Linux - если что есть VirtualBox с WinXP). Есть знания ассемблера (баловался когда-то с написанием своей ОС), с дизасемблерами никогда ранее не работал.

 , ,

KivApple
()

Определение трансформации ThinkPad

Форум — Desktop

Под виндой Thinkpad X230T реагировал на тот факт, что его крышку повернули таким образом, что он стал планшетом. Каким образом можно детектить это событие под Linux и выполнять какую-нибудь команду?

 ,

KivApple
()

Вращение изображения на экране относительно текущего положения

Форум — Desktop

У моего новоприобретённого ноутбукопланшета есть кнопка для ручного вращения дисплея (с датчиком ориентации буду разбираться потом, если он есть, чего я не знаю пока что). Под виндой оно вело себя следующим образом: в цикле переключало варианты ориентации дисплея.

Я знаю про xrandr --rotate left|right|inverted|normal, но этого мне недостаточно. Я бы хотел, чтобы ориентация переключалась относительно текущей ориентации дисплея. То есть если сейчас normal, то становилось left, если сейчас left, то становилось inverted, если сейчас inverted, то становилось right, и, наконец, если сейчас right, то становилось normal.

Как бы такое организовать?

 

KivApple
()

Авторизация по сканеру отпечатков пальцев

Форум — Desktop

Приобретённый мною ThinkPad X230T обладает сканером отпечатков пальцев, хочу использовать его как альтернативу паролю при входе в систему.

Установлен дисплейный менеджер SDDM.

$ cat /etc/pam.d/sddm
#%PAM-1.0

auth      sufficient pam_fprintd.so
auth      substack system-login

account         include         system-login
password        include         system-login
session         include         system-login

Предварительно я установил fprintd и считал с его помощью свои отпечатки пальцев.

Теперь можно не вводить пароль, а сразу нажать Enter, при этом включается сканер отпечатков пальцев и если провести пальцем, то авторизация пройдёт. Если ввести пароль, то всё равно включается сканер отпечатков и ожидает, что я проведу пальцем. А я так не хочу. Я хочу чтобы было правило ИЛИ. То есть при верном пароле сканировать отпечаток не должно быть необходимо, а сразу должна проходить авторизация.

Как такое сделать?

 

KivApple
()

Написание плагина для Clang

Форум — Development

Решил потыкать Clang API. Допустим, я хочу пробежаться по AST, найти некоторые места, которые удовлетворяют определённым критериям и модифицировать их.

С первыми двумя пунктами проблем особых нет - я создал плагин для Clang, который создаёт ASTConsumer, переопределил метод HandleToplevelDecl, который по условию запускает RecursiveASTVisitor на некоторых элементах. Наконец, я нахожу места, которые хотел бы модифицировать. А вот с модификацией есть проблемы.

Допустим, я знаю, что интересующие меня ноды являются дочерними элементами CompoundStmt. Я могу переопределить TraverseCompoundStmt, вручную бежать по его детям и вызывать TraverseStmt для них. При этом visitXXX устанавливает флаг, который я потом проверяю. При выполнении условия я могу присвоить *it (где it - итератор из диапазона от stmt->child_begin() до stmt->child_end()) новый узел. В принципе это работает. Например, я могу создать пустой CompoundStmt и заменить узел на него. После этого я вижу с помощью objdump (а также по дампу AST), что соответствующие инструкции исчезают. Но что если я хочу более сложных изменений?

Например, я хочу создать метку (LabelStmt). И тут я натыкаюсь на проблему, что LabelStmt хочет LabelDecl, который в свою очередь хочет IdentifierInfo. Каким образом создать новый идентификатор и получить его IdentifierInfo? Если указать вместо нормального IdentifierInfo nullptr, то clang предсказуемо падает. Каких-либо нормальных конструкторов или статических методов для создания IdentifierInfo в самом IdentifierInfo я не заметил. Значит IdentifierInfo должен создавать кто-то другой. Но кто? Как вообще генерировать новые идентификаторы?

 ,

KivApple
()

Указатель на указатель на функцию

Форум — Development

Небольшой и, возможно, глупый вопрос по Си.

void f(void (**some_func)(void*)) {
    (*some_func)(some_func);
}
...
struct {
    void (*func_ptr)(void*);
    ...
} some_struct = { ... };
f((void (**)(void*))&some_struct);

Является ли приведённый выше код корректным?

По сути дела он базируется на двух предположениях:

1) Адрес первого поля структуры совпадает с адресом структуры. Пустые байты для выравнивания (если компилятор решил их добавить) всегда добавляются после поля, но не перед ним.

2) Указатель на указатель на функцию это самый обычный указатель на данные. Указатель на функцию сам по себе может быть особенным. Например, если речь идёт о гарвардской архитектуре, в которой код и данные имеют разные адресные пространства. Соответственно, указатель на функцию может быть чем-то принципиально иным, нежели указатель на данные (даже банально разрядности адресов в памяти программ и памяти данных могут быть разными). Но указатель на указатель на функцию это уже самое обычное число.

Верны ли эти предположения для всех архитектур, где имеет место быть Си?

 

KivApple
()

Расширенный Си

Форум — Talks

Не так давно я презентовал здесь свой велосипед - c-oop-gen: ООП в Си. А именно генератор сишного кода в ООП стиле из XML описания. Тогда мне объяснили, что XML не лучшая идея для представления программного кода. Так что встречайте мой новый велосипед - https://github.com/KivApple/c_ext.

Это что-то вроде препроцессора для Си, который добавляет в язык несколько новых конструкций.

Все эти конструкции связаны с определением структур. Во-первых, структуры теперь можно наследовать.

struct A {
    int a;
};

struct B: A {
    int b;
};

При этом очень немаловажен тот факт, что указатель на B совместим с указателем на A (но не наоборот). Под капотом там незаметно вставляется приведение типов, если оно необходимо.

Во-вторых, у структуры теперь могут быть методы:

struct A {
    int f();
};

int A::f() {
    return 100500;
}

Инлайнить (реализовывать методы прямо внутри структуры) нельзя, но я считаю, что это не очень нужно, ибо это таки С, а не С++ и программист должен явно определять, в каком исполняемом модуле окажется функция (а если очень хочется, может описать её как static в момент реализации и поместить в заголовочный файл).

Всем нестатическим методам автоматически передаётся указатель на структуру this, с которым можно свободно работать.

В-третьих, у структур теперь могут быть статические члены:

struct A {
    static int i;
    static void test();
};

int A::i;

void A::test() {
    ...
}

В-четвёртых, у структуры могут быть виртуальные методы. Правда, чтобы они работали, нужно обязательно объявить конструктор - нестатичный метод с именем construct, а также вызвать его до любого вызова виртуального метода.

В-пятых, можно явно обратиться к родительской реализации. Как-то так:

struct A {
    void f();
};
struct B: A {
    void f();
};

void B::f() {
    this->A::f();
}

Данный транслятор должен понимать большинство gcc-змов. Во всяком случае я проверил его на нескольких стандартных заголовочниках (а они полны gcc-змов) и он всё скушал, а на выходе получился валидный код. Однако крайне не рекомендуется применять всякие атрибуты к структурам и их членам, если вы используете новые возможности (если нет, то определения не будут изменены, а вот если транслятор в них уж полез, то он может съесть что-то неподдерживаемое).

Также транслятор сам по себе понимает директивы #line и генерирует свои после окончания обработки. То есть ему можно подавать на вход результат работы любого препроцессора (cpp, m4 и т. п.), а в сообщениях об ошибках компилятора будут адекватные указания, где произошла ошибка.

Несмотря на то, что транслятор имеет достаточно информации для того, чтобы отлавливать многие ошибки (например, неопределённые идентификаторы или несовместимость типов), он старается этого не делать и падать только на тех ошибках, которые специфичны именно для него (например, попытка унаследоваться не от структуры).

Логика простая: компиляторы обычно выдают очень хорошие сообщения об ошибках, а мои сообщения могут оказаться недостаточно информативными. К тому же мой транслятор выходит после первой же ошибки, а большинство компиляторов выводят все найденные. А ещё я могу воспринять за ошибку какой-то расширение компилятора. Так что я просто стараюсь оставить насколько это возможным неизменными все непонятные места.

В общем, вот такие дела. Жду ваших комментариев.

Особенно меня интересует вопрос: что делать с конструкторами, собственно? Можно вызывать их в C++ стиле - то есть в момент объявления переменной (или выделения памяти). Это хорошо, конечно, что никто не забудет вызвать конструкторы, но как-то недостаточно Plain C-way. А что если мы хотим выделить память, а конструктор вызывать лишь спустя какое-то время? От ответа на этот вопрос зависит и судьба деструкторов - если конструктор гарантированно вызывается, то мне не проблема автоматически вызвать деструктор. Но в текущем виде автоматическому вызову деструктора не место (а вдруг объект не был сконструирован?).

Также интересует нужность перегрузки функций. Я могу сделать манглинг имён (а чтобы сохранить совместимость с Си, не менять имя первого объявления функции), но насколько он нужен?

P. S.: Планы на будущее: поддержка лямбд и асинхронного программирования.

UPD1: Добавил поддержку анонимных функций, в том числе с захватом переменных из текущего контекста по ссылке или по значению. См. README.

UPD2: Добавил начальную поддержку самого главного, ради чего всё затевалось. А именно - поддержку асинхронного программирования. Теперь можно вызвать функцию, возвращающую void и ожидающую делегата в качестве последнего аргумента (у меня делегат - это любая структура, у которой первое поле это указатель на функцию, которая первым аргументом принимает указатель на эту структуру), не указывая значение для этого самого аргумента. В результате случится магия и текущая функция станет асинхронной (функция, которая подтвергается данной метаморфозе, должна возвращать void и не принимать переменное число аргументов). Переменные, которые используются одновременно по разные стороны от асинхронного вызова будут сохранятся в специальную структуру состояния. Сама структура состояния будет создана с помощью malloc при входе в асинхронную функцию и освобождена при выходе (будь то естественное завершение или выход с помощью return). Пока в реализации есть косяки, но я их исправлю. Внутри асинхронной функции категорически не рекомендуется использовать goto, ибо это сломает алгоритм определения какие переменные нужно сохранять при асинхронном вызове.

 , , , ,

KivApple
()

Каталог для кеша

Форум — Development

Допустим, я пишу приложение на Python и ему требуется кешировать некоторые данные между своими вызовами. Это именно кеш, а не настройки. В смысле, что их можно безболезненно удалить, просто следующий запуск приложения будет дольше.

Как мне определить, в какую папку стоит сохранять эти данные (это несколько файлов)?

Под Linux понятное дело можно сохранить куда-нибудь в ~/.cache/my-app-name, но хотелось бы более универсального решения, чтобы оно работало под всеми ОС.

Умеет ли Python сам по себе или с каким-нибудь модулем такое? Или только вручную определять ОС и генерировать путь к каталогу для кеша?

tempfile.mktemp не подходит, потому что он на многих Linux выдаст путь в /tmp, который находится на ram-диске и его содержимое теряется при перезагрузке. Я ничего не имею против пользователей, которые хотят так поступить с кешем, но всё это должно потребовать от них каких-то действий (например, тот же каталог ~/.cache придётся сделать ссылкой на каталог в /tmp, это не стандартное поведение ОС).

 

KivApple
()

Выбор ThinkPad

Форум — Talks

Давно думал о приобретении какого-нибудь ThinkPad, а теперь наконец-то появились свободные финансы для этого.

Смотрю пока в сторону S230. Он вроде достаточно актуальный (например, есть порты USB 3.0). Стоит? Или лучше всё же X230?

Обязательно хочу с тачскрином и Core i7. Бюджет 25к. Рассматриваю возможность последующего апгрейда (вроде докупить оперативки и SSD).

Где их покупать? На Ebay с доставкой из США? Стоит ли использовать услуги пересыльщиков? Стоит ли брать восстановленный Thinkpad?

 , ,

KivApple
()

Поиск элемента в списка по его 2D-координатам

Форум — Development

С этой задачей по идее должны часто стакливаться разработчики игр, различных редакторов и просто графических тулкитов.

А именно: допустим, у нас есть набор графических объектов. Для простоты примем, что они все имеют прямоугольную форму (в крайнем случае всегда можно описать прямоугольник вокруг многоугольника или эллипса и если этот объект прошёл первичные проверки допроверять уже точно), а их стороны параллельны осям координат. У нас есть некоторое окно, через которое пользователь эти объекты просматривает. То есть одновременно он может видеть и взаимодействовать не со всеми объектами, а только с теми, которые имеют пересечение с прямоугольником окна просмотра. Хоть у нас и 2D пространство, но у объектов должно быть что-то типа Z-индекса, чтобы если два из них наложились, то какой-то всегда рисовался поверх другого и не было неоднозначности (для простоты можно принять, что самым верхним объектом является тот, который последний добавлен в список, если мы хотим поднять объект, то удаляем его из списка и добавляем заново).

Теперь допустим, пользователь кликает или даже просто водит мышью по этому окну просмотра. Нужно при любом событии быстро определить, над чем находится указатель мыши (чтобы при наведении подсветить объект, а при клике выполнить какое-то действие). Это нужно сделать быстро, ведь обработчику движения мыши нельзя сильно тупить. Также необходимо легко менять координаты объектов (например, пользователь схватил объект и потащил его мышью, хотя тут можно считерить - запоминать какой объект тащим и дальнейшие операции всегда вести только с ним, а вносить реальные изменения в список лишь при отпускании мыши).

Я понимаю, что это по-любому реализовано в тысячах различных программ и игр и сами подходы должны быть общеизвестны. В какую сторону копать? Как называется сам этот процесс, какие можете посоветовать структуры данных для хранения объектов (простой словарь не подойдёт - ведь у нас есть две координаты, к тому же ещё и размеры объектов, которые могут сильно различаться)?

Или, возможно, я занимаюсь преждевременной оптимизацией и на самом деле, если объектов не миллионы (а даже в какой-нибудь стратегии обычно миллионов юнитов нет, как и в различных редакторах - человек просто не осилилт управлять мышью таким количеством объектов), то можно забить и делать тупой перебор обычного линейного списка и проверять, попадает ли мышь в bounding box?

 ,

KivApple
()

Модель дерева с динамической подгрузкой

Форум — Development

Пишу приложение с использованием Python, Qt5 и PySide. Делаю модель дерева с динамической подгрузкой (наследуюсь от QAbstractItemModel).

В принципе алгоритм действий прост - каждый узел по дефолту не грузит своих детей, а лишь имеет флаг loaded = False. Также мною переопределены canFetchMore (возвращает !loaded) и fetchMode (собственно, загружает данные и делает loaded = True).

Пока я не загрузил детей узла, я не знаю их количества и вообще есть ли они. Однако если rowCount возвращает ноль, то такой узел невозможно развернуть и соответственно реальные данные никогда подгружены не будут. Решение: возвращаем единицу, если loaded == False.

Теперь перед нами встаёт новая проблема. После разворачивания узла, у которого нет детей, значок с плюсиком никуда не девается (хотя rowCount уже возвращает 0 вместо 1) и это выглядит очень некрасиво.

Что делать в этом случае? Как дать QTreeView понять, что у узла нет детей на самом деле?

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

 ,

KivApple
()

RSS подписка на новые темы