Приложение на GTK#
Пример собирает GTK4-приложение из исходников через meson и доводит его до установленного Flatpak. Программа пишется здесь же, поэтому пример повторяется целиком.
GTK-приложения работают на среде org.astra.Gtk. В ней GTK3 и GTK4
(libgtk-3.so.0 версии 3.24 и libgtk-4.so.1 версии 4.8), GLib 2.74,
Pango, Cairo, GdkPixbuf, а также то, что обычно нужно рядом: libsecret,
libnotify, libappindicator3, libnss3, libatk, libcups.
Подготовка#
sudo flatpak install astra-main org.astra.Gtk//1.8.6
sudo flatpak install astra-extended org.astra.gtkSdk//1.8.6
Дерево примера#
gtk-hello/
|-- gtk-hello.yaml
`-- src/
|-- meson.build
|-- main.c
|-- ru.example.GtkHello.desktop
|-- ru.example.GtkHello.metainfo.xml
`-- icons/
`-- 128x128/
`-- app.png
В каталог icons/128x128 кладётся любой PNG размером 128 на 128.
Исходный код#
src/main.c:
#include <gtk/gtk.h>
static void on_activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "GTK Hello");
gtk_window_set_default_size(GTK_WINDOW(window), 360, 120);
GtkWidget *label = gtk_label_new("GTK4 внутри Flatpak");
gtk_window_set_child(GTK_WINDOW(window), label);
gtk_window_present(GTK_WINDOW(window));
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("ru.example.GtkHello",
G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
src/meson.build:
project('gtk-hello', 'c', version: '1.0')
gtk_dep = dependency('gtk4')
executable('gtk-hello',
'main.c',
dependencies: gtk_dep,
install: true)
Устанавливается только бинарник. Desktop-файл, описание AppStream и иконки
подкладывает aft-app из полей секции files, поэтому в meson их дублировать
не нужно.
src/ru.example.GtkHello.desktop:
[Desktop Entry]
Type=Application
Name=GTK Hello
Name[ru]=Пример на GTK
Comment=Минимальное приложение на GTK4
Exec=gtk-hello
Icon=gtk-hello
Terminal=false
Categories=Utility;
src/ru.example.GtkHello.metainfo.xml:
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>ru.example.GtkHello</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<name>GTK Hello</name>
<summary>Минимальное приложение на GTK4</summary>
<description>
<p>Пример приложения на GTK4 для проверки сборки во Flatpak.</p>
</description>
<launchable type="desktop-id">ru.example.GtkHello.desktop</launchable>
</component>
Манифест#
gtk-hello.yaml:
version: "1.0"
metadata:
id: ru.example.GtkHello
name: "GTK Hello"
version: "1.0"
arch: amd64
branch: stable
runtime:
id: org.astra.Gtk
version: "1.8.6"
sdk: org.astra.gtkSdk
source:
type: sourcedir
sourcedir:
path: ./src
buildDeps:
packages:
- libgtk-4-dev
- meson
- ninja-build
buildCommands:
- meson setup build --prefix=/app --buildtype=release
- meson compile -C build
- meson install -C build
files:
command: gtk-hello
desktop: ./src/ru.example.GtkHello.desktop
metainfo: ./src/ru.example.GtkHello.metainfo.xml
icons-dir: ./src/icons
permissions:
sockets: [wayland, fallback-x11]
devices: [dri]
shares: [ipc]
filesystems: [xdg-pictures]
persist: [.config, .local/share]
export:
repository: ./repo
Сборка и установка#
cd gtk-hello
aft-app validate gtk-hello.yaml
sudo aft-app build gtk-hello.yaml
sudo flatpak remote-add --if-not-exists --no-gpg-verify local-repo ./repo
sudo flatpak install -y local-repo ru.example.GtkHello
flatpak run ru.example.GtkHello
Проверка готовой сборки:
aft-analyzer ru.example.GtkHello
Если программа уже установлена в системе#
Источник system переносит во Flatpak то, что уже стоит на машине. Он
пригождается, когда исходников нет, пакет собрать неоткуда, а работающая
установка есть:
version: "1.0"
metadata:
id: ru.example.LegacyTool
name: "Устаревшая утилита"
version: "3.1"
arch: amd64
branch: stable
runtime:
id: org.astra.Gtk
version: "1.8.6"
sdk: org.astra.gtkSdk
source:
type: system
system:
binary: /usr/bin/legacy-tool
patterns:
- /usr/share/legacy-tool
- /etc/legacy-tool
includeOwningPackages: true
files:
command: legacy-tool
permissions:
sockets: [wayland, fallback-x11]
devices: [dri]
shares: [ipc]
persist: [.config]
export:
repository: ./repo
Поле binary принимает путь к программе или её имя в PATH. Список
patterns добавляет файлы и каталоги, которые сама программа по
зависимостям не тянет. Флаг includeOwningPackages включает в сборку
пакеты-владельцы целиком: так надёжнее, но сборка выходит крупнее.
Для источников system и tar deb-зависимости не разбираются: состав
задаёт сам источник. Что программа требует на самом деле, покажет analyze по
разделяемым библиотекам:
aft-app analyze --system /usr/bin/legacy-tool \
--runtime org.astra.Gtk --runtime-version 1.8.6
Тонкости GTK#
Схемы GSettings нужно скомпилировать, иначе приложение падает при первом
обращении к настройкам. При сборке из исходников это делает meson. Если схема
приезжает готовым файлом, её кладут в share/glib-2.0/schemas и компилируют
командой перед экспортом:
commands:
pre-export:
- glib-compile-schemas files/share/glib-2.0/schemas
Команды секции pre-export выполняются на сборочной машине, а не в песочнице
SDK, и рабочим каталогом им служит каталог сборки, где лежит дерево files.
Поэтому путь пишется относительно него, а сама утилита должна быть установлена
на машине: glib-compile-schemas приезжает с пакетом libglib2.0-bin.
Тема оформления и иконки берутся из среды, а не с хоста. Приложение в песочнице может выглядеть иначе, чем вне её, и это не признак поломки.
Работа с файлами идёт через портал: диалог открытия возвращает приложению уже открытый файл. Доступ ко всему домашнему каталогу почти никогда не нужен, достаточно нужных каталогов XDG.
GTK3 и GTK4 стоят в среде рядом, поэтому приложения на обеих версиях собираются
на одну среду. Библиотеку разработки для GTK3 в сборочных зависимостях зовут
libgtk-3-dev.