diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9952fa..e5601ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,7 @@ variables: variables: FDO_DISTRIBUTION_VERSION: "35" # Update this to trigger a container rebuild - FDO_DISTRIBUTION_TAG: "2021-12-15.0" + FDO_DISTRIBUTION_TAG: "2022-01-07.2" build-fedora-container: extends: @@ -35,6 +35,14 @@ build-fedora-container: clang-devel gstreamer1-devel gstreamer1-plugins-base-devel + gstreamer1-plugins-bad-free-devel + ninja-build + pkg-config + python3-devel + python3-pip + python3-setuptools + FDO_DISTRIBUTION_EXEC: >- + pip3 install meson rustfmt: extends: @@ -42,6 +50,7 @@ rustfmt: - .fdo.distribution-image@fedora stage: lint script: + - meson build - cargo fmt --version - cargo fmt -- --color=always --check @@ -51,6 +60,7 @@ test-stable: - .fdo.distribution-image@fedora stage: test script: + - meson build - rustc --version - cargo build --color=always --all-targets - cargo test --color=always @@ -63,6 +73,7 @@ rustdoc: variables: RUSTDOCFLAGS: "-Dwarnings" script: + - meson build - rustdoc --version - cargo doc --no-deps @@ -72,5 +83,6 @@ clippy: - .fdo.distribution-image@fedora stage: extras script: + - meson build - cargo clippy --version - cargo clippy --color=always --all-targets -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 3f39b61..52b3a7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.44" @@ -66,6 +75,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "byteorder" version = "1.4.3" @@ -289,6 +304,26 @@ dependencies = [ "system-deps 5.0.0", ] +[[package]] +name = "gettext-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364" +dependencies = [ + "gettext-sys", + "locale_config", +] + +[[package]] +name = "gettext-sys" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa9e06ab9e7514cc9ae668ea3b71ea1536259d767dff0289ac23ad134f99929" +dependencies = [ + "cc", + "temp-dir", +] + [[package]] name = "gimli" version = "0.26.1" @@ -440,6 +475,7 @@ name = "gst_pipeline_studio" version = "0.1.0" dependencies = [ "anyhow", + "gettext-rs", "glib", "gstreamer", "gtk4", @@ -585,6 +621,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.103" @@ -597,6 +639,19 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +[[package]] +name = "locale_config" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" +dependencies = [ + "lazy_static", + "objc", + "objc-foundation", + "regex", + "winapi", +] + [[package]] name = "log" version = "0.3.9" @@ -615,6 +670,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "matches" version = "0.1.9" @@ -682,6 +746,35 @@ dependencies = [ "autocfg", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.27.1" @@ -819,6 +912,23 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "ron" version = "0.3.0" @@ -1042,6 +1152,12 @@ dependencies = [ "version-compare", ] +[[package]] +name = "temp-dir" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab" + [[package]] name = "thiserror" version = "1.0.30" diff --git a/Cargo.toml b/Cargo.toml index c4e543e..93d8125 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] gtk = { version = "0.3", package = "gtk4" } anyhow = "1" +gettext-rs = {version = "0.7", features = ["gettext-system"]} glib = "0.14" gstreamer = "0.17" log = "0.4.11" diff --git a/README.md b/README.md index ffef6c6..5054075 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,22 @@ Check https://rustup.rs for alternative installation options. ### Ubuntu/Debian/etc ```sh +apt install python3-pip ninja-build pkgconfig +pip3 install --user meson apt install libgtk-4-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev ``` ### Fedora/RedHat/SuSE/etc ```sh -dnf install gtk4-devel gstreamer1-devel gstreamer1-plugins-base-devel +dnf install python3-pip ninja-build pkgconfig +pip3 install meson +dnf install gtk4-devel gstreamer1-devel gstreamer1-plugins-base-devel python3-pip ninja-build pkgconfig ``` ## Getting started ```sh +meson builddir cargo run ``` diff --git a/build-aux/cargo.sh b/build-aux/cargo.sh new file mode 100644 index 0000000..caec9ac --- /dev/null +++ b/build-aux/cargo.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +export MESON_BUILD_ROOT="$1" +export MESON_SOURCE_ROOT="$2" +export CARGO_TARGET_DIR="$MESON_BUILD_ROOT"/target +export CARGO_HOME="$CARGO_TARGET_DIR"/cargo-home +export OUTPUT="$3" +export BUILDTYPE="$4" +export APP_BIN="$5" + + +if [ $BUILDTYPE = "release" ] +then + echo "RELEASE MODE" + cargo build --manifest-path \ + "$MESON_SOURCE_ROOT"/Cargo.toml --release && \ + cp "$CARGO_TARGET_DIR"/release/"$APP_BIN" "$OUTPUT" +else + echo "DEBUG MODE" + cargo build --manifest-path \ + "$MESON_SOURCE_ROOT"/Cargo.toml && \ + cp "$CARGO_TARGET_DIR"/debug/"$APP_BIN" "$OUTPUT" +fi + diff --git a/build-aux/dist-vendor.sh b/build-aux/dist-vendor.sh new file mode 100644 index 0000000..e28f21d --- /dev/null +++ b/build-aux/dist-vendor.sh @@ -0,0 +1,9 @@ +#!/bin/sh +export SOURCE_ROOT="$1" +export DIST="$2" + +cd "$SOURCE_ROOT" +mkdir "$DIST"/.cargo +cargo vendor | sed 's/^directory = ".*"/directory = "vendor"/g' > $DIST/.cargo/config +# Move vendor into dist tarball directory +mv vendor "$DIST" diff --git a/build-aux/meson/postinstall.py b/build-aux/meson/postinstall.py new file mode 100644 index 0000000..6a3ea97 --- /dev/null +++ b/build-aux/meson/postinstall.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from os import environ, path +from subprocess import call + +prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local') +datadir = path.join(prefix, 'share') +destdir = environ.get('DESTDIR', '') + +# Package managers set this so we don't need to run +if not destdir: + print('Updating icon cache...') + call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')]) + + print('Updating desktop database...') + call(['update-desktop-database', '-q', path.join(datadir, 'applications')]) + + print('Compiling GSettings schemas...') + call(['glib-compile-schemas', path.join(datadir, 'glib-2.0', 'schemas')]) + + diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..e11444b --- /dev/null +++ b/meson.build @@ -0,0 +1,70 @@ +project('gst_pipeline_studio', + version: '0.1.0', + meson_version: '>= 0.50.0', + default_options: [ 'warning_level=2', + ], + license: 'GPL-3.0-or-later', +) +i18n = import('i18n') + +dependency('glib-2.0', version: '>= 2.66') +dependency('gio-2.0', version: '>= 2.66') +dependency('gtk4', version: '>= 4.0.0') +dependency('gstreamer-1.0', version: '>= 1.18') +dependency('gstreamer-base-1.0', version: '>= 1.18') +dependency('gstreamer-plugins-base-1.0', version: '>= 1.18') +dependency('gstreamer-plugins-bad-1.0', version: '>= 1.18') + +find_program('cargo', required: true) +find_program('glib-compile-resources', required: true) + +glib_compile_schemas = find_program('glib-compile-schemas', required: true) +desktop_file_validate = find_program('desktop-file-validate', required: false) +appstream_util = find_program('appstream-util', required: false) + +version = meson.project_version() +prefix = get_option('prefix') +bindir = prefix / get_option('bindir') +localedir = prefix / get_option('localedir') + +datadir = prefix / get_option('datadir') +pkgdatadir = datadir / meson.project_name() +iconsdir = datadir / 'icons' +podir = meson.source_root () / 'po' +gettext_package = meson.project_name() +base_id = 'org.freedesktop.dabrain34.GstPipelineStudio' + +if get_option('profile') == 'development' + application_id = base_id + '.Devel' + profile = 'Devel' + name_prefix = '(Development) ' + vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip() + if vcs_tag == '' + version_suffix = '-devel' + else + version_suffix = '-@0@'.format (vcs_tag) + endif +else + profile = '' + version_suffix = '' + name_prefix = '' + application_id = base_id +endif + +cargo_sources = files( + 'Cargo.toml', + 'Cargo.lock', +) + +#subdir('data') +subdir('src') +#subdir('po') + + +meson.add_dist_script( + 'build-aux/dist-vendor.sh', + meson.source_root(), + join_paths(meson.build_root(), 'meson-dist', meson.project_name() + '-' + version) +) + +meson.add_install_script('build-aux/meson/postinstall.py') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..06c5b93 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,12 @@ +option ( + 'profile', + type: 'combo', + choices: [ + 'default', + 'development' + ], + value: 'default', + description: 'The build profile for Authenticator. One of "default" or "development".' +) + + diff --git a/src/about.rs b/src/about.rs new file mode 100644 index 0000000..e1dd8f1 --- /dev/null +++ b/src/about.rs @@ -0,0 +1,46 @@ +// about.rs +// +// Copyright 2021 Stéphane Cerveau +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-only +use crate::app::GPSApp; +use crate::config; +use gettextrs::gettext; +use gtk::prelude::*; + +use gtk::ApplicationWindow; + +pub fn display_about_dialog(app: &GPSApp) { + let window: ApplicationWindow = app + .builder + .object("mainwindow") + .expect("Couldn't get window"); + let about_dialog = gtk::AboutDialogBuilder::new() + .modal(true) + .program_name("GstPipelineStudio") + .version(config::VERSION) + .comments(&gettext("Draw your own GStreamer pipeline")) + .website("https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio") + .authors(vec!["Stéphane Cerveau".to_string()]) + .artists(vec!["Stéphane Cerveau".to_string()]) + .translator_credits(&gettext("translator-credits")) + .logo_icon_name(config::APP_ID) + .license_type(gtk::License::Gpl30) + .transient_for(&window) + .build(); + + about_dialog.show(); +} diff --git a/src/app.rs b/src/app.rs index 7bf28ea..d832bb1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -21,9 +21,9 @@ use glib::Value; use gtk::gdk::Rectangle; use gtk::prelude::*; use gtk::{ - gdk::BUTTON_SECONDARY, AboutDialog, Application, ApplicationWindow, Builder, Button, - CellRendererText, FileChooserAction, FileChooserDialog, ListStore, Paned, PopoverMenu, - ResponseType, Statusbar, TreeView, TreeViewColumn, Viewport, Widget, + gdk::BUTTON_SECONDARY, Application, ApplicationWindow, Builder, Button, CellRendererText, + FileChooserAction, FileChooserDialog, ListStore, Paned, PopoverMenu, ResponseType, Statusbar, + TreeView, TreeViewColumn, Viewport, Widget, }; use gtk::{gio, gio::SimpleAction, glib, graphene}; use once_cell::unsync::OnceCell; @@ -32,6 +32,7 @@ use std::collections::HashMap; use std::rc::{Rc, Weak}; use std::{error, ops}; +use crate::about; use crate::logger; use crate::pipeline::{Pipeline, PipelineState}; use crate::plugindialogs; @@ -524,21 +525,10 @@ impl GPSApp { }); let app_weak = self.downgrade(); - application - .lookup_action("about") - .expect("Unable to find action") - .dynamic_cast::() - .expect("Unable to cast to SimpleAction") - .connect_activate({ - move |_, _| { - let app = upgrade_weak!(app_weak); - let about_dialog: AboutDialog = app - .builder - .object("dialog-about") - .expect("Couldn't get window"); - about_dialog.show(); - } - }); + self.connect_app_menu_action("about", move |_, _| { + let app = upgrade_weak!(app_weak); + about::display_about_dialog(&app); + }); let app_weak = self.downgrade(); self.connect_button_action("button-add-plugin", move |_| { diff --git a/src/common.rs b/src/common.rs index b9ddee7..46660cf 100644 --- a/src/common.rs +++ b/src/common.rs @@ -20,8 +20,6 @@ use anyhow::Result; use gstreamer as gst; -pub const APPLICATION_NAME: &str = "org.freedesktop.gst-pipeline-studio"; - pub fn init() -> Result<()> { unsafe { x11::xlib::XInitThreads(); diff --git a/src/config.rs.in b/src/config.rs.in new file mode 100644 index 0000000..74c714e --- /dev/null +++ b/src/config.rs.in @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pub static APP_ID: &str = @APP_ID@; +pub static VERSION: &str = @VERSION@; diff --git a/src/gps.ui b/src/gps.ui index c39f847..e175c0b 100644 --- a/src/gps.ui +++ b/src/gps.ui @@ -85,11 +85,6 @@ - - GstPipelineStudio - Stéphane Cerveau - True - 100 1 diff --git a/src/main.rs b/src/main.rs index b575a0c..2651046 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,8 +19,10 @@ // SPDX-License-Identifier: GPL-3.0-only #[macro_use] mod macros; +mod about; mod app; mod common; +mod config; mod graphmanager; #[macro_use] mod logger; @@ -35,7 +37,7 @@ use crate::common::init; fn main() { // gio::resources_register_include!("compiled.gresource").unwrap(); init().expect("Unable to init app"); - let application = gtk::Application::new(Some(common::APPLICATION_NAME), Default::default()); + let application = gtk::Application::new(Some(config::APP_ID), Default::default()); application.connect_startup(|application| { GPSApp::on_startup(application); }); diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..c45ce25 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,56 @@ +conf = configuration_data() +conf.set_quoted('APP_ID', application_id) +conf.set_quoted('VERSION', version + version_suffix) + +configure_file( + input: 'config.rs.in', + output: 'config.rs', + configuration: conf +) + +# Copy the config.rs output to the source directory. +run_command( + 'cp', + join_paths(meson.build_root(), 'src', 'config.rs'), + join_paths(meson.source_root(), 'src', 'config.rs'), + check: true +) + +rust_sources = files( + 'graphmanager/graphview.rs', + 'graphmanager/link.rs', + 'graphmanager/mod.rs', + 'graphmanager/node.rs', + 'graphmanager/port.rs', + 'about.rs', + 'app.rs', + 'common.rs', + 'logger.rs', + 'macros.rs', + 'main.rs', + 'pipeline.rs', + 'plugindialogs.rs', + 'settings.rs', + +) + +sources = [cargo_sources, rust_sources] + +cargo_script = find_program(join_paths(meson.source_root(), 'build-aux/cargo.sh')) +cargo_release = custom_target( + 'cargo-build', + build_by_default: true, + input: sources, + output: meson.project_name(), + console: true, + install: true, + install_dir: get_option('bindir'), + command: [ + cargo_script, + meson.build_root(), + meson.source_root(), + '@OUTPUT@', + get_option('buildtype'), + meson.project_name(), + ] +) diff --git a/src/settings.rs b/src/settings.rs index 03936b6..2125fec 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; -use crate::common; +use crate::config; use crate::logger; #[derive(Debug, Serialize, Deserialize, Default)] @@ -37,7 +37,7 @@ impl Settings { fn get_settings_file_path() -> PathBuf { let mut path = glib::user_config_dir(); - path.push(common::APPLICATION_NAME); + path.push(config::APP_ID); path.push("settings.toml"); path }