devzone.org.ua/post/moyi-pershi-kroky-v-gtk.md
2025-11-01 14:28:20 +02:00

99 lines
No EOL
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Мої перші кроки в GTK
## Передмова
Не так давно захотілось зробити простенький браузер для [протоколу Gemini](https://devzone.org.ua/tag/gemini). Зокрема - додати детекцію Geo-IP капсул, власний пошук на базі [Manticore](https://devzone.org.ua/tag/manticore) та інтегрувати екосистему [Yggdrasil](https://devzone.org.ua/tag/yggdrasil).
Для обраного протоколу задача виглядала тривіальною, залишалось обрати графічний фреймворк і накидати туди крутих функцій.
Я постійний користувач Linux, вибір був між Qt та GTK. З Qt вже поверхнево знайомий, в рамках одного з проектів, що довелось апгрейдити і разом з тим оновлювати залежності API (досі приходить спам після обов'язкової реєстрації для завантаження останньої SDK)
Але оскільки завжди був користувачем середовища GNOME, все таки пішов стежкою GNU і вирішив глянути що там і як робиться на практиці.
Забігаючи вперед, скажу що займався професійно виключно веб розробкою, добре знаю суміжні мови, патерни і фреймворки. Але це була фактично моя перша десктоп програма, яку захотілось написати з нуля.
Заради цікавості вбив у пошук знайому для себе комбінацію "PHP-GTK" і щось там побачив! Ну, а оскільки вже чимало часу провів з PHP, то написати браузер цією мовою було доволі простою задачею - в запасі вже було з десяток власних бібліотек, лишалось їх тільки натягнути на віконний API і все.
Отже, знайшов пару прикладів, написав простенький код виклику вікна - працює, значить працюватиме й інше!
## Інформація в мережі
Перше з чим зіткнувся, на відміну від Qt, PHP/JS та інших поп-технологій, пошукові видачі по GTK - порівняно порожні або посилаються на якісь старі мануали по другій версії.
Звісно є [офіційна документація](https://docs.gtk.org), але без розуміння загальної картини.. взагалі складно.. як, що, до чого. На ютубі теж тотальний кошмар, але частково є англомовний контент в основному по двійці, якості не краще. Краще не дивитись. Довелось пробиратись через тернові хащі розуміння самому. Вирішив нарешті задати дільне питання Chat GPT і Haiku, останній до речі доволі точно і лаконічно генерує приклади на Python, C та C++
## Документація
В принципі, вона є але доволі скупа і потребує деякого рівня для входу. Але так якщо писати програму по інструкціям ШІ та паралельно читати документацію по кожному методу і його типам то по-трохи можна в'їхати що до чого.
## Поняття Widget
В якийсь момент, почав розуміти що є деякі класи, з яких подібно блокам конструктора, складається вікно і всі його елементи. Ці класи потрібно зібрати до купи в рамках іншого класу-віджету у потрібному порядку і вкладеності: копки, поля та інше - формуючи в результаті вікно і заголовок (який тут теж є віджетом).
Згодом, працюючи безпосередньо з компонуванням, стало відомо про такий інструмент як Glade, який дозволяє робити те само не в коді а через UI (як Unity для ігор) а проект експортувати - в XML, який в свою чергу, потім можна імпортувати в об'єкти - вже засобами класу [Builder](https://docs.gtk.org/gtk4/class.Builder.html).
В принципі, використовувати Glade чи ні - справа вподобань. Особисто мені не подобається UI та XML як явище в ООП, але офіційного аналогу JSON не знайшов, тому й далі описую віджети об'єктами в коді програми. Варто зазначити, що для GTK 4, Glade вже не використовується, а на його офіційному сайті висить [заглушка nginx](https://glade.gnome.org). Тут на зміну для четвірки приходить нова і мабуть єдина, неофіційна програма і новий формат проекту файлів - [Cambalache](https://gitlab.gnome.org/jpu/cambalache).
## Ієрархія і наслідування
Через певний час роботи, виявиться що деяких методів в прикладах, які описує ШІ немає в документації класу і це не помилка! Як виявляється, на сторінці кожного віджету можна побачити [дерево наслідування](https://docs.gtk.org/gtk4/class.Box.html#hierarchy), і воно там проілюстроване не спроста
![gtk box hierarchy](https://i.imgur.com/fi9MnBx.png)
Таким чином, в пошуках певної функції для тюнінгу програми, вже можна читати не тільки документацію робочого класу, але й обов'язково його батьківського елементу - де виявляється ціла купа нових методів про які на сторінці самого методу не згадується окрім клікабельної мапи наслідування. Це була суто моя, користувацька неуважність і як наслідок самостійна реалізація функціональності яка вже була давно доступна, просто з інструментами які знаходяться рівнем вище у батьківських класах та групах об'єктів.
Якщо пишете програму на C, то ймовірно це буде простіше, оскільки компілятор підсвітить та авто-доповнить семантику. Але в моєму випадку - був шлях пробивного першопрохідця на PHP, який ще й писав порт на PHP-CPP мабуть довше ніж сам браузер.
По цій темі можна ще додати наступне. Якщо ви пишете першу програму GTK на C++, то ймовірно вже віднайшли і користуєтесь враппером [gtkmm](https://gtkmm.org) (і його сателітами - glibmm і giomm) - така собі абстракція, яка спростить код але добряче заплутає в офіційній документації для C через свою абстрагованість. Частина API в gtkmm досі не реалізована. Також офіційні класи GTK 4, на відміну від GTK 3, вже оголошені як final, тобто не можуть наслідуватись і передбачають або агрегацію або композицію. Разом з тим, gtkmm все ще дозволяє наслідування (подібно Qt) і тут звісно теж не дуже зрозуміло як краще проектувати програму згідно стандартам і що на gtkmm чекатиме завтра. Але бібліотека безумовно зручна, дійсно зменшує об'єм коду в рази три.
Все таки мені здається оптимальним писати першу програму GTK на С а не C++, чи наприклад Rust. C, не зважаючи на потенційно більшу кількість коду і відсутність ООП, на мою думку, буде простішим шляхом для початківця, зокрема у вивченні того як влаштована ієрархія фреймворку, події, використання пам'яті. І вже тільки потім варто переходити на абстрактний рівень вище. Для себе все ще не визначився бо все життя провів в ООП, і вже не уявляю без цього програму більшу за "hello world"
## Типи даних і допоміжні функції
Низькорівневі бібліотеки [Gio](https://docs.gtk.org/gio)/[Glib](https://docs.gtk.org/glib) містять чимало зручних функцій для роботи з кодуванням, розміткою, сокетами і взагалі все що потрібно для роботи з контентом. Багато з них наслідують STL. Коли я вперше відкрив для себе розділ функцій то чомусь мені згадалось різноманіття препроцесору розмітки PHP - де є все для роботи з веб, а у веб зараз є все.
Таким чином, майже не використовую STL бо майже на кожну функцію і тип даних, в середовищі GTK для них є розширена і адаптована реалізація.
## Робота з контентом
Якщо говорити про вивід даних в контексті браузеру, який у моєму випадку має відображати простий gemtext з клікабельними посиланнями, починається деякий дисонанс після роботи з JS/HTML.
По-перше в GTK є тільки два відомих мені віджети для тексту - [Label](https://docs.gtk.org/gtk4/class.Label.html) і [TextView](https://docs.gtk.org/gtk4/class.TextView.html)
`Label` - це по суті блок для невеликого тексту, який може підтримувати розмітку або звичайний текст. Розмітка при цьому використовує формат [Pango](https://docs.gtk.org/Pango), тобто це такий собі мінімальний варіант HTML з декількома тегами і класами, що використовується для інших, специфічних для стаціонарних програм цілей. Поле `Label` не розраховане на великий об'єм даних, тому як і варто очікувати мігрантам з HTML - сенс його однозначний - невеличкий опис до якогось блоку і все. Текст на 100Кб відправить вашу програму в роздуми на 10 секунд, особливо якщо спробуєте відформатувати [Layout](https://docs.gtk.org/Pango/class.Layout.html) своїм способом, наприклад перерахувати word-wrap чи відмалювати інакше шрифти перед додаванням у віджет.
Тим не менше, усі дороги і поради "бувалих" ведуть саме на `Label`, але якщо залізти у вихідний код інших, швидких GTK браузерів то побачимо, що часто використовується багаторядкове текстове поле вводу `TextView`. По суті, це аналог поля `textarea`, в якому достатньо сховати курсор засобами CSS (наприклад, через `caret-color: transparent`) та перевести віджет в режим [readonly](https://docs.gtk.org/gtk4/method.Editable.set_editable.html).
Цей віджет так само підтримує розмітку, події, користувацькі теги а також буфер, в який можна складати і відмальовувати невеликий текст по мірі прокрутки контенту, як багато хто і робить що і являє собою розгадку швидкодії рендерингу великих документів.
Говорячи про прокрутку. Ще не знаю як в GTK 4, але в GTK 3 віджет, який не підтримує засоби скролу, потрібно додати у відповідний контейнер [Viewport](https://docs.gtk.org/gtk3/class.Viewport.html). Інакше ви довго не будете розуміти чому ваш текст сам по собі відскролюється на верх, наприклад при перемиканні табів `Label` віджету `Notebook`. Так само в іншому, очевидно вектор спрощення торкається не тільки візуальної але і внутрішньої частини GTK - розробник повинен сам реалізувати потрібні йому набори, навіть якщо вони здаються тривіальними і такими, що здавалось би, мають бути з коробки.
Щодо CSS - тут від нього тільки три літери, і мабуть три властивості в залежності від двох тегів, які оберете :)
Є віджет для картинки ([Picture](https://docs.gtk.org/gtk4/class.Picture.html)) і є для більш простої піктограми, наприклад для віджету кнопки ([Image](https://docs.gtk.org/gtk4/class.Image.html)) якщо треба більше - пишіть самі. Мінімалізм.
## Робота з діями
Фреймворк базується на системі подій, тому, хто добре знайомий з JavaScript / Node.js, буде просто розібратись.
Кожен віджет здатен оголошувати власні [Action](https://docs.gtk.org/gtk4/actions.html), [ActionGroup](https://docs.gtk.org/gio/iface.ActionGroup.html), а також звертатись до глобальних рівнів вікна (`win`) та застосунку (`app`)
Взагалі тема велика і було б добре написати про неї окремо, але нагадаю, особливо бекендерам: на систему дій потрібно звернути увагу в першу чергу і не писати передачу викликів методами класів, ін'єкцією залежностей і т.д., як робив це я спочатку.
## Спільнота
В GNU спілньота живе десь в чистилищах своїх гітлабів та інших екзотичних місцях. На гітхабі звісно ваша присутність не допоможе, доведеться по всім баг-репортам реєструватись на окремих сайтах. А для підтримки користуватись [форумом](https://discourse.gnome.org/). В принципі 2-3 користувача час від часу відповідають (схоже на співробітників фундації) але особисто мені це не зовсім зручно, в порівнянні з системою Issues та PR на GitHub.
Для себе, в навчанні, й досі користуюсь ШІ, потім читаю документацію, пишу код, і так по колу. Пошук Google тут видає аж нічого цікавого. В принципі форум читати не дуже інформативно бо старі теми там закриваються і коментувати туди вже не можна.
## Висновки
Мені чимось подобається графічне середовище GNOME: можливо своєю простотою та однорідністю застосунків, що схоже за філософією на MacOS, користувачем і фаном якої я був довгий час. Й досі, використовую GOME на машині iMac (оскільки для розробки користуюсь Linux)
GTK має більш інтуїтивний, матеріальний інтерфейс, в той час як Qt та різноманітні JS/Electron чомусь асоціюються з пластиком, де кожна програма має різні властивості, таймінги відгуку, що не зручно коли фокусуєшся на роботі.
Звісно з трійкою все пішло мобільним шляхом, робочий стіл став пустим місцем, а програми такі прості що виконують буквально одну функцію. Все що більш менш в побуті - на Qt.
Власне кажучи, буду намагатись й надалі в'їхати в тему GTK, а коли все вляжеться і засвоїться то може буде сенс написати якийсь навчальний матеріал по одній конкретній темі. Ну а зараз, думаю краще поділитись тим що маю - першим враженням з точки зору розробника, і як бачу GTK під капотом в цілому після декількох місяців користування.
Щодо браузера - наразі в нього утворилось дві гілки:
* [PHP-GTK3](https://github.com/YGGverse/Yoda/tree/PHP-GTK3) - більш функціональна але ймовірно вже архівна версія, оскільки писати на GTK 3 не бачу сенсу а вкладатись в контрибуцію бібліотеки Zend / GTK 4 зараз не цікаво. По суті включає базові функції - відкриває файли, протоколи [nex](https://devzone.org.ua/post/protokol-nex-lehka-alternatyva-gemini) та gemini. Останньою фічею була авторизація сертифікатами TLS (коди групи 60), тому якщо комусь цікаво - може поколупатись в робочих прикладах багатопоточної реалізації PHP/GTK так і обробки протоколу Gemini зокрема.
* [CPP-GTK4](https://github.com/YGGverse/Yoda/tree/CPP-GTK4) - остання версія, стан чернетки, в якій я досі не визначився з патерном. Можливо взагалі переключусь на C або відкрию нову гілку на Rust, який мене давно цікавить своїм пакетним менеджером.
Поки що все, діліться вашим досвідом знайомства з GTK, якщо такий є ;)