Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions cx.modal.Reflection.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@
"url" : "./",
"branch" : "HEAD"
}
],
"config-opts" : [
"--libdir=lib"
]
}
]
Expand Down
14 changes: 9 additions & 5 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ gnome = import('gnome')

application_id = 'cx.modal.Reflection'

pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name()
iconsdir = get_option('datadir') / 'icons'
prefix = get_option('prefix')
bindir = prefix / get_option('bindir')
localedir = prefix / get_option('localedir')

subdir('reflection-app/data')
subdir('reflection-app/src')
subdir('reflection-app/po')
datadir = prefix / get_option('datadir')
pkgdatadir = datadir / meson.project_name()
iconsdir = datadir / 'icons'
podir = meson.project_source_root() / 'po'

subdir('reflection-app')

gnome.post_install(
glib_compile_schemas: true,
Expand Down
10 changes: 0 additions & 10 deletions reflection-app/data/cx.modal.Reflection.desktop.in

This file was deleted.

12 changes: 12 additions & 0 deletions reflection-app/data/cx.modal.Reflection.desktop.in.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Desktop Entry]
Name=Reflection
Comment=Collaboratively take meeting notes, even when there's no internet
Exec=reflection
Icon=@icon@
Terminal=false
Type=Application
Categories=GNOME;GTK;Utility;Network;Office;
# Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=GTK;Adwaita;Modal;p2panda;p2p;peer-to-peer;localfirst;local-first;notes;note-taking;minutes;meeting;multiplayer;multi-player;collaboration;collaborative;real-time;writing;text;editor;pad;
StartupNotify=true
DBusActivatable=true
3 changes: 1 addition & 2 deletions reflection-app/data/cx.modal.Reflection.metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@
</recommends>

<releases>
<release version="0.1" date="2025-11-22">
<url type="details">https://example.org/changelog.html#version_1.0.1</url>
<release version="0.1" date="2025-12-23">
<description translate="no">
<p>Initial preview release.</p>
<ul>
Expand Down
2 changes: 1 addition & 1 deletion reflection-app/data/cx.modal.Reflection.service.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[D-BUS Service]
Name=cx.modal.Reflection
Name=@application_id@
Exec=@bindir@/reflection --gapplication-service
42 changes: 26 additions & 16 deletions reflection-app/data/meson.build
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Desktop file
desktop_conf = configuration_data()
desktop_conf.set('icon', application_id)
desktop_file = i18n.merge_file(
input: 'cx.modal.Reflection.desktop.in',
output: 'cx.modal.Reflection.desktop',
type: 'desktop',
po_dir: '../po',
install: true,
install_dir: get_option('datadir') / 'applications'
type: 'desktop',
input: configure_file(
input: '@0@.desktop.in.in'.format(application_id),
output: '@BASENAME@',
configuration: desktop_conf,
),
output: '@0@.desktop'.format(application_id),
po_dir: podir,
install: true,
install_dir: datadir / 'applications',
)

desktop_utils = find_program('desktop-file-validate', required: false)
Expand All @@ -13,11 +20,11 @@ if desktop_utils.found()
endif

appstream_file = i18n.merge_file(
input: 'cx.modal.Reflection.metainfo.xml.in',
output: 'cx.modal.Reflection.metainfo.xml',
po_dir: '../po',
install: true,
install_dir: get_option('datadir') / 'metainfo'
input: 'cx.modal.Reflection.metainfo.xml.in',
output: '@0@.metainfo.xml'.format(application_id),
po_dir: podir,
install: true,
install_dir: datadir / 'metainfo',
)

appstreamcli = find_program('appstreamcli', required: false, disabler: true)
Expand All @@ -34,13 +41,16 @@ test('Validate schema file',
args: ['--strict', '--dry-run', meson.current_source_dir()])


# D-Bus service file
service_conf = configuration_data()
service_conf.set('bindir', get_option('prefix') / get_option('bindir'))
service_conf.set('application_id', application_id)
service_conf.set('bindir', bindir)
configure_file(
input: 'cx.modal.Reflection.service.in',
output: 'cx.modal.Reflection.service',
configuration: service_conf,
install_dir: get_option('datadir') / 'dbus-1' / 'services'
input: 'cx.modal.Reflection.service.in',
output: '@0@.service'.format(application_id),
configuration: service_conf,
install: true,
install_dir: datadir / 'dbus-1/services',
)

subdir('icons')
Expand Down
3 changes: 3 additions & 0 deletions reflection-app/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
subdir('data')
subdir('src')
subdir('po')
94 changes: 65 additions & 29 deletions reflection-app/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ mod imp {
#[property(get, nullable)]
pub service: RefCell<Option<Service>>,
pub startup_error: RefCell<Option<Error>>,
pub service_startup_task: RefCell<Option<glib::JoinHandle<()>>>,
#[property(get)]
pub system_settings: SystemSettings,
}
Expand All @@ -77,36 +78,19 @@ mod imp {

impl ApplicationImpl for ReflectionApplication {
fn startup(&self) {
let service: Result<Service, Error> =
glib::MainContext::default().block_on(async move {
let private_key = secret::get_or_create_identity().await?;

let mut data_path = glib::user_data_dir();
data_path.push("Reflection");
data_path.push(private_key.public_key().to_string());
fs::create_dir_all(&data_path)?;
let data_dir = gio::File::for_path(data_path);

let service = Service::new(&private_key, Some(&data_dir));
service.startup().await?;
Ok(service)
});

match service {
Ok(service) => {
self.service.replace(Some(service));
}
Err(error) => {
error!("Failed to start service: {error}");
self.startup_error.replace(Some(error));
}
}

self.parent_startup();

gtk::Window::set_default_icon_name(config::APP_ID);
}

fn shutdown(&self) {
glib::MainContext::default().block_on(async move {
// Make sure service startup finished
if let Some(handle) = self.service_startup_task.take() {
handle
.await
.expect("Service startup to complete on shutdown");
}
if let Some(service) = self.obj().service() {
service.shutdown().await;
}
Expand All @@ -115,6 +99,8 @@ mod imp {
}

fn activate(&self) {
self.parent_activate();

self.obj().new_window();
}
}
Expand All @@ -130,10 +116,10 @@ glib::wrapper! {
}

impl ReflectionApplication {
pub fn new(application_id: &str, flags: &gio::ApplicationFlags) -> Self {
pub fn new() -> Self {
glib::Object::builder()
.property("application-id", application_id)
.property("flags", flags)
.property("application-id", config::APP_ID)
.property("flags", gio::ApplicationFlags::empty())
.build()
}

Expand Down Expand Up @@ -271,12 +257,62 @@ impl ReflectionApplication {
]);
}

async fn create_service(&self) -> Result<Service, Error> {
let private_key = secret::get_or_create_identity().await?;

let mut data_path = glib::user_data_dir();
data_path.push("Reflection");
data_path.push(private_key.public_key().to_string());
fs::create_dir_all(&data_path)?;
let data_dir = gio::File::for_path(data_path);

let service = Service::new(&private_key, Some(&data_dir));
service.startup().await?;

Ok(service)
}

fn new_window(&self) -> Window {
let window = Window::new(self);
window.set_service(self.service());

if let Some(error) = self.imp().startup_error.borrow().as_ref() {
window.display_startup_error(error);
}

if let Some(service) = self.service() {
window.set_service(Some(service));
} else if self.imp().service_startup_task.borrow().is_none() {
let handle = glib::spawn_future_local(clone!(
#[weak(rename_to = obj)]
self,
async move {
let service = obj.create_service().await;

match service {
Ok(service) => {
for window in obj.windows() {
if let Ok(window) = window.downcast::<Window>() {
window.set_service(Some(&service));
}
}
obj.imp().service.replace(Some(service));
}
Err(error) => {
error!("Failed to start service: {error}");
for window in obj.windows() {
if let Ok(window) = window.downcast::<Window>() {
window.display_startup_error(&error);
}
}
obj.imp().startup_error.replace(Some(error));
}
}
}
));

self.imp().service_startup_task.replace(Some(handle));
}

window.present();
window
}
Expand Down
12 changes: 3 additions & 9 deletions reflection-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,19 @@ fn main() -> glib::ExitCode {
.expect("Unable to set the text domain encoding");
textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");

// Load resources
let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file");
gio::resources_register(&res);
let ui_res = gio::Resource::load(UI_RESOURCES_FILE).expect("Could not load UI gresource file");
gio::resources_register(&ui_res);

// Create a new GtkApplication. The application manages our main loop,
// application windows, integration with the window manager/compositor, and
// desktop features such as file opening and single-instance applications.
let app = ReflectionApplication::new("cx.modal.Reflection", &gio::ApplicationFlags::empty());
gtk::glib::set_application_name("Reflection");
gtk::init().expect("Could not start GTK4");

info!("Reflection ({})", APP_ID);
info!("Version: {}", VERSION);
info!("Datadir: {}", PKGDATADIR);

// Run the application. This function will block until the application
// exits. Upon return, we have our exit code to return to the shell. (This
// is the code you see when you do `echo $?` after running a command in a
// terminal.
let app = ReflectionApplication::new();
app.run()
}

Expand Down
10 changes: 4 additions & 6 deletions reflection-app/src/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
gnome = import('gnome')

blueprints = custom_target('blueprints',
input: files(
'shortcuts-dialog.blp'
Expand All @@ -20,10 +18,10 @@ conf = configuration_data()
conf.set_quoted('APP_ID', application_id)
conf.set_quoted('VERSION', meson.project_version())
conf.set_quoted('GETTEXT_PACKAGE', 'reflection')
conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
conf.set_quoted('LOCALEDIR', localedir)
conf.set_quoted('PKGDATADIR', pkgdatadir)

configure_file(
config_file = configure_file(
input: 'config.rs.in',
output: 'config.rs',
configuration: conf
Expand All @@ -32,7 +30,7 @@ configure_file(
# Copy the config.rs output to the source directory.
run_command(
'cp',
meson.project_build_root() / 'reflection-app/src' / 'config.rs',
config_file,
meson.project_source_root() / 'reflection-app/src' / 'config.rs',
check: true
)
Expand All @@ -56,7 +54,7 @@ cargo_build = custom_target(
output: meson.project_name(),
console: true,
install: true,
install_dir: get_option('bindir'),
install_dir: bindir,
command: [
'env', cargo_env,
cargo_bin, 'build',
Expand Down
Loading