Chandra
view release on metacpan or search on metacpan
- Add Chandra::Store - Persistent key-value storage for Chandra apps
0.10 2026-04-02
- Add Chandra::Shortcut - keyboard shortcuts and global hotkeys
0.09 2026-04-01
- Fix Makefile to identify BSD's that should use GTK/WebKit2
0.08 2026-04-01
- Fix removing unnecessary call_method overhead when calling internal XSUBS.
- Adds Native OS desktop notifications
0.07 2026-03-31
- Port code to XS (all methods now in C)
- Add global css and js chain methods to Chandra::App
- Extend routes with a way to assign custom css and js per route
0.06 2026-03-30
- Add system tray integration and example
- Another attempt at fixing windows to run
- Start porting code into XS, using the INCLUDE technique
examples/form_example.pl view on Meta::CPAN
value => 90,
});
});
$form->group('Notifications' => sub {
$form->checkbox('notify_email', {
label => 'Email notifications',
checked => 1,
});
$form->checkbox('notify_desktop', {
label => 'Desktop notifications',
});
$form->radio('frequency', {
label => 'Digest Frequency',
options => [
{ value => 'instant', label => 'Instant' },
{ value => 'daily', label => 'Daily' },
{ value => 'weekly', label => 'Weekly' },
],
examples/modal.pl view on Meta::CPAN
# ââ Custom modal ââââââââââââââââââââââââââââââââââââââââââ
$app->bind('show_custom', sub {
Chandra::Modal->show($app,
title => 'About This App',
width => 450,
content => '<div style="text-align:center;">'
. '<h2 style="margin:0 0 8px;">Modal Demo</h2>'
. '<p style="color:var(--chandra-text-muted);">Version 1.0.0</p>'
. '<p>Built with <strong>Chandra</strong> — '
. 'a Perl desktop GUI framework.</p>'
. '<hr>'
. '<p style="font-size:0.85em;color:var(--chandra-text-muted);">'
. 'Modals, toasts, themes, tables, and components — all in XS.</p>'
. '</div>',
buttons => [
{ label => 'Close', class => 'primary', action => 'close' },
],
);
});
lib/Chandra/Form.pm view on Meta::CPAN
$form->hidden('csrf_token', { value => 'abc123' });
$form->submit('Save Settings');
# Render to HTML
my $html = $form->render;
=head1 DESCRIPTION
Chandra::Form provides form building helpers with automatic two-way
data binding between Perl and the DOM for Chandra desktop applications.
Forms are built by chaining field methods, then rendered to HTML via
C<render()>. When used with C<Chandra::App>, the generated JavaScript
handles form submission, change events, and value synchronization
through the Chandra bridge.
=head1 METHODS
=head2 new
lib/Chandra/Notify.pm view on Meta::CPAN
use strict;
use warnings;
# Load XS functions from Chandra bootstrap
use Chandra ();
our $VERSION = '0.25';
=head1 NAME
Chandra::Notify - Native OS desktop notifications
=head1 SYNOPSIS
use Chandra::Notify;
# Simple notification
Chandra::Notify->send(
title => 'Download Complete',
body => 'report.pdf has finished downloading',
);
lib/Chandra/Notify.pm view on Meta::CPAN
timeout => 5000,
);
# Check if supported
if (Chandra::Notify->is_supported) {
Chandra::Notify->send(title => 'Hello', body => 'World');
}
=head1 DESCRIPTION
Chandra::Notify provides native desktop notifications across platforms:
=over 4
=item * macOS: Uses UNUserNotificationCenter (10.15+) or NSUserNotification
=item * Linux: Uses libnotify if available, falls back to notify-send
=item * Windows: Uses toast notifications (MessageBox as fallback)
=back
lib/Chandra/Notify.pm view on Meta::CPAN
=head1 PLATFORM NOTES
=head2 macOS
Requires macOS 10.8+ for NSUserNotification, 10.15+ for UNUserNotificationCenter.
The app must be properly signed to display notifications in some cases.
=head2 Linux
Requires a notification daemon (most desktop environments have one).
libnotify.so.4 is preferred; falls back to notify-send CLI.
=head2 Windows
Currently uses MessageBox as a fallback. Full toast notification support
is planned for a future release.
=head1 SEE ALSO
L<Chandra>, L<Chandra::App>
lib/Chandra/Pack.pm view on Meta::CPAN
# Create structure
file_mkpath($lib_dir);
file_mkpath($share);
# AppRun
my $apprun = file_join($app_dir, 'AppRun');
file_spew($apprun, $self->_generate_launcher_linux());
chmod 0755, $apprun;
# Desktop entry
file_spew(file_join($app_dir, lc($safe) . '.desktop'), $self->_generate_desktop());
# Copy script
file_copy($self->{script}, file_join($usr, 'share', 'script.pl'));
# Copy deps
$self->_copy_deps($lib_dir);
# Icon
if ($self->{icon} && file_exists($self->{icon})) {
file_copy($self->{icon}, file_join($app_dir, lc($safe) . file_extname($self->{icon})));
lib/Chandra/Pack.pm view on Meta::CPAN
}
sub _create_appimage {
my ($self, $app_dir, $appimagetool) = @_;
my $safe = _safe_name($self->{name});
my $appimage_path = file_join($self->{output}, "$safe.AppImage");
# Ensure proper AppDir structure
# AppRun should already exist from build_linux
# Ensure .desktop file is at root level
my $desktop_file = file_join($app_dir, lc($safe) . '.desktop');
unless (file_is_file($desktop_file)) {
return { success => 0, error => "Missing .desktop file" };
}
# Run appimagetool
my $cmd = "\Q$appimagetool\E \Q$app_dir\E \Q$appimage_path\E 2>&1";
my $output = `$cmd`;
if ($? != 0) {
return { success => 0, error => "appimagetool failed: $output" };
}
# Make executable
lib/Chandra/Pack.pm view on Meta::CPAN
my ($self) = @_;
my $perl = $self->{perl};
return <<LAUNCHER;
\@echo off
set DIR=%~dp0
set PERL5LIB=%DIR%lib;%PERL5LIB%
"$perl" "%DIR%script.pl" %*
LAUNCHER
}
sub _generate_desktop {
my ($self) = @_;
my $safe = lc(_safe_name($self->{name}));
my $icon_ext = '';
$icon_ext = file_extname($self->{icon}) if $self->{icon} && file_exists($self->{icon});
return <<DESKTOP;
[Desktop Entry]
Type=Application
Name=$self->{name}
Exec=./AppRun
Icon=${safe}${icon_ext}
lib/Chandra/Store.pm view on Meta::CPAN
# Reload picks up external changes
$s->reload;
# Via Chandra::App
my $app = Chandra::App->new(title => 'My App', ...);
my $store = $app->store; # name derived from app title
=head1 DESCRIPTION
Chandra::Store provides persistent key-value storage for Chandra desktop
applications, backed by a JSON file at C<~/.chandra/E<lt>nameE<gt>/store.json>
by default.
Keys support dot notation for nested structures (e.g. C<window.width>).
Writes are atomic: data is written to a C<.tmp.PID> file then renamed into
place. File locking (flock) prevents corruption from concurrent processes.
=head1 METHODS
=head2 new(%args)
t/63_pack.t view on Meta::CPAN
my $win = $p->_generate_launcher_windows;
like($win, qr/\@echo off/i, 'windows launcher has echo off');
like($win, qr/PERL5LIB/, 'windows launcher sets PERL5LIB');
like($win, qr/script\.pl/, 'windows launcher runs script.pl');
}
# ââ Desktop Entry Generation ââââââââââââââââââââââââââââââââââââââââ
{
my $p = Chandra::Pack->new(script => $script, name => 'Test App');
my $desktop = $p->_generate_desktop;
like($desktop, qr/\[Desktop Entry\]/, 'desktop has header');
like($desktop, qr/Type=Application/, 'desktop is Application type');
like($desktop, qr/Name=Test App/, 'desktop has name');
like($desktop, qr/Exec=\.\/AppRun/, 'desktop exec is AppRun');
}
# ââ Platform Detection âââââââââââââââââââââââââââââââââââââââââââââââ
{
my $p = Chandra::Pack->new(script => $script);
my $plat = $p->platform;
if ($^O eq 'darwin') {
is($plat, 'macos', 'detects macos');
} elsif ($^O eq 'MSWin32') {
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(*wv_svp);
PUTBACK;
call_method("exit", G_DISCARD);
FREETMPS; LEAVE;
}
(void)hv_stores(hv, "_started", newSViv(0));
}
# ---- notify(%args) - send a desktop notification ----
int
notify(self, ...)
SV *self
CODE:
{
ChandraNotification notif;
I32 i;
memset(¬if, 0, sizeof(notif));
( run in 1.026 second using v1.01-cache-2.11-cpan-df04353d9ac )