App-XUL
view release on metacpan or search on metacpan
lib/App/XUL.pm view on Meta::CPAN
my ($self, %opts) = @_;
$self->{'name'} = $opts{'name'} || do { die "Error: no app name given - new(name => <string>)\n" };
$self->{'windows'} = [];
$self->{'bindings'} = {};
return $self
}
sub bind
{
my ($id, $event, $coderef) = @_;
$Singleton->{'bindings'}->{$id.':'.$event} = $coderef;
return $Singleton;
}
sub add
{
my ($self, $window_xml) = @_;
die "Error: add() only accepts a single window tag as first argument\n"
if $window_xml !~ /^<window/;
push @{$self->{'windows'}}, $window_xml;
return $self;
}
sub bundle
{
my ($self, %opts) = @_;
my $os = $opts{'os'} || die "Error: no os given - bundle(os => <string>)\n";
my $path = $opts{'path'} || die "Error: no path given - bundle(path => <string>)\n";
my $utilspath = $opts{'utilspath'} || die "Error: no utils path given - bundle(utilspath => <string>)\n";
$self->{'debug'} = $opts{'debug'} || 0;
#print Dumper($self);
#exit;
##############################################################################
if ($os eq 'chrome') {
my $name = $self->{'name'};
my $tmpdir = create_structured_tree(
$name => {
'start_macosx.pl' => [$self->_get_file_startpl('chrome','macosx')],
'start_win.pl' => [$self->_get_file_startpl('chrome','win')],
'start_linux.pl' => [$self->_get_file_startpl('chrome','linux')],
'chrome.manifest' => ['manifest chrome/chrome.manifest'."\n"],
'application.ini' => [$self->_get_file_macosx_appini()],
#'MyApp.icns' => [],
'chrome' => {
# for older XUL.framework's we need the chrome.manifest here!
'chrome.manifest' => [$self->_get_file_macosx_chromemanifest()],
'content' => {
#'AppXUL.js' => [],
#'AppXULServer.js' => [],
$self->_get_file_macosx_xulfiles(),
#'main.xul' => [$self->_get_file_macosx_mainxul()],
},
},
'defaults' => {
'preferences' => {
'prefs.js' => [$self->_get_file_macosx_prefs()],
},
},
'perl' => {
'server' => {
#'server.pl' => [$self->_get_file_macosx_serverpl()],
},
'modules' => {
'Eventhandlers.pm' => [$self->_get_file_macosx_eventhandlers()],
'App' => {
'XUL' => {
#'XML' => [],
#'Object' => [],
},
},
},
},
'extensions' => {},
'updates' => {
'0' => {},
},
}
);
# copy misc files into tmpdir
fcopy($utilspath.'/AppXUL.js',
$tmpdir->base().'/'.$name.'/chrome/content/AppXUL.js');
fcopy($utilspath.'/server.pl',
$tmpdir->base().'/'.$name.'/perl/server/server.pl');
fcopy($utilspath.'/../lib/App/XUL/XML.pm',
$tmpdir->base().'/'.$name.'/perl/modules/App/XUL/XML.pm');
fcopy($utilspath.'/../lib/App/XUL/Object.pm',
$tmpdir->base().'/'.$name.'/perl/modules/App/XUL/Object.pm');
# chmod certain files
chmod(0755, $tmpdir->base().'/'.$name.'/start_macosx.pl');
chmod(0755, $tmpdir->base().'/'.$name.'/start_win.pl');
chmod(0755, $tmpdir->base().'/'.$name.'/start_linux.pl');
# move tmpdir to final destination
rename($tmpdir->base().'/'.$name, $path);
}
##############################################################################
elsif ($os eq 'macosx') {
my $name = $self->{'name'};
my $tmpdir = create_structured_tree(
$name.'.app' => {
'Contents' => {
'Info.plist' => [$self->_get_file_maxosx_infoplist()],
'Frameworks' => {
#'XUL.framework' => {},
},
'MacOS' => {
'start.pl' => [$self->_get_file_startpl('macosx')],
},
'Resources' => {
'chrome.manifest' => ['manifest chrome/chrome.manifest'."\n"],
'application.ini' => [$self->_get_file_macosx_appini()],
#'MyApp.icns' => [],
'chrome' => {
# for older XUL.framework's we need the chrome.manifest here!
'chrome.manifest' => [$self->_get_file_macosx_chromemanifest()],
'content' => {
#'AppXUL.js' => [],
#'AppXULServer.js' => [],
$self->_get_file_macosx_xulfiles(),
#'main.xul' => [$self->_get_file_macosx_mainxul()],
},
},
'defaults' => {
'preferences' => {
'prefs.js' => [$self->_get_file_macosx_prefs()],
},
},
'perl' => {
'server' => {
#'server.pl' => [$self->_get_file_macosx_serverpl()],
},
'modules' => {
'Eventhandlers.pm' => [$self->_get_file_macosx_eventhandlers()],
'App' => {
'XUL' => {
#'XML' => [],
#'Object' => [],
},
},
},
},
'extensions' => {},
'updates' => {
'0' => {},
},
},
}
}
);
# copy misc files into tmpdir
die "Error: no XUL.framework found in /Library/Frameworks - please install XUL framework from mozilla.org\n"
unless -d '/Library/Frameworks/XUL.framework';
dircopy('/Library/Frameworks/XUL.framework',
$tmpdir->base().'/'.$name.'.app/Contents/Frameworks/XUL.framework');
fcopy($utilspath.'/Appicon.icns',
$tmpdir->base().'/'.$name.'.app/Contents/Resources/'.$name.'.icns');
fcopy($utilspath.'/AppXUL.js',
$tmpdir->base().'/'.$name.'.app/Contents/Resources/chrome/content/AppXUL.js');
#fcopy('../../misc/AppXULServer.js',
# $tmpdir->base().'/'.$name.'.app/Contents/Resources/chrome/content/AppXULServer.js');
fcopy($utilspath.'/server.pl',
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/server/server.pl');
fcopy($utilspath.'/../lib/App/XUL/XML.pm',
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/modules/App/XUL/XML.pm');
fcopy($utilspath.'/../lib/App/XUL/Object.pm',
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/modules/App/XUL/Object.pm');
# chmod certain files
chmod(0755, $tmpdir->base().'/'.$name.'.app/Contents/MacOS/start.pl');
# move tmpdir to final destination
rename($tmpdir->base().'/'.$name.'.app', $path);
}
else {
die "Error: os '$os' not implemented yet\n";
}
}
################################################################################
sub _get_file_macosx_eventhandlers
{
my ($self) = @_;
my $eventhandlers = '';
foreach my $name (keys %{$self->{'bindings'}}) {
$eventhandlers .= "'".$name."' => \n".Dumper($self->{'bindings'}->{$name}).",\n";
}
return
'package Eventhandlers;'."\n".
'use App::XUL::XML;'."\n".
'$App::XUL::XML::RunInsideServer = 1;'."\n".
'our $AUTOLOAD;'."\n".
'sub AUTOLOAD {'."\n".
' $App::XUL::XML::AUTOLOAD = $AUTOLOAD;'."\n".
' return App::XUL::XML::AUTOLOAD(@_);'."\n".
'}'."\n".
'sub get {'."\n".
' return {'."\n".
$eventhandlers.
' };'."\n".
'}'."\n".
'1;'."\n";
}
sub _get_file_macosx_prefs
{
my ($self) = @_;
return <<EOFSRC
pref("toolkit.defaultChromeURI", "chrome://$self->{'name'}/content/main.xul");
/* debugging prefs */
pref("browser.dom.window.dump.enabled", true);
pref("javascript.options.showInConsole", true);
pref("javascript.options.strict", true);
pref("nglayout.debug.disable_xul_cache", true);
pref("nglayout.debug.disable_xul_fastload", true);
EOFSRC
}
sub _get_file_macosx_xulfiles
{
my ($self) = @_;
my @files = ();
my $w = 0;
foreach my $window_xml (@{$self->{'windows'}}) {
my $xml =
'<?xml version="1.0"?>'."\n".
'<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>'."\n".
$window_xml;
push @files, ($w == 0 ? 'main' : 'sub'.$w).'.xul', [$xml];
$w++;
}
return @files;
# return
# '<?xml version="1.0"?>'."\n".
# '<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>'."\n".
# $self->{'xml'};
#<window id="mw" title="$self->{'name'}" width="800" height="200"
# xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
# xmlns:html="http://www.w3.org/1999/xhtml">
# <script src="AppXUL.js"/>
# ...
#</window>
}
sub _get_file_macosx_chromemanifest
{
my ($self) = @_;
return 'content '.$self->{'name'}.' file:content/'."\n";
}
sub _get_file_macosx_appini
{
my ($self) = @_;
return <<EOFSRC
[App]
Version=1.0
Vendor=Me
Name=$self->{'name'}
BuildID=myid
ID={generated id}
[Gecko]
MinVersion=1.8
MaxVersion=2.*
EOFSRC
}
sub _get_file_startpl
{
my ($self, $os, $type) = @_;
lib/App/XUL.pm view on Meta::CPAN
<UNREGISTER> := {
action: "unregister",
id: <ID>,
name: <STRING>
}
<SETATTR> := {
action: "setattr",
id: <ID>,
name: <STRING>,
value: <STRING>
}
<GETATTR> := {
action: "getattr",
id: <ID>,
name: <STRING>
}
Here are some examples of client requests:
{event:"click", id:"btn"}
Here are some examples of server responses:
{action:"update", id:"btn", attributes:{label:"Alrighty!"}}
{action:"remove", id:"btn"}
{action:"create", parent:"main", content:"<button .../>"}
=head3 Application bundling for Mac OS X
Mac applications are simply directories whose names end with ".app"
and have a certain structure and demand certain files to exist.
This is the structure of a XUL application wrapped inside a Mac application
as created by App::XUL (files are blue, directories are black):
=begin html
<pre>
MyApp.app/
Contents/
<span style="color:blue;font-weight:bold">Info.plist</span>
Frameworks/
XUL.framework/
<i>The XUL Mac framework</i>
MacOS
<span style="color:blue;font-weight:bold">start.pl</span> (Perl-Script)
Resources
<span style="color:blue;font-weight:bold">application.ini</span>
<span style="color:blue;font-weight:bold">MyApp.icns</span>
chrome/
<span style="color:blue;font-weight:bold">chrome.manifest</span>
content/
<span style="color:blue;font-weight:bold">AppXUL.js</span>
<span style="color:blue;font-weight:bold">myapp.xul</span>
defaults/
preferences/
<span style="color:blue;font-weight:bold">prefs.js</span>
perl/
server/
<span style="color:blue;font-weight:bold">server.pl</span>
modules/
<i>All Perl modules the server depends on</i>
extensions/
updates/
0/
</pre>
=end html
The various files have specific functions. When the MyApp.app is
clicked, the B<start.pl> program is executed which then starts the
server and the client:
=over 1
=item Info.plist
Required by Mac OS X. This is the place where certain basic information
about the application is read by Mac OS X, before anything else is done.
For example, here the start.pl program is defined as the entry point
of the application.
=item start.pl
First program to be executed. Starts server and client.
=item application.ini
Setups the XUL application. Defines which *.xul files to load,
name of application etc.
=item AppXUL.js
Defines all Javascript functions used by App::XUL to manage the
communication with the server.
=item myapp.xul
Defines the basic UI for the XUL application.
=item prefs.js
Sets some preferences for the XUL application.
=item server.pl
This starts the server.
=back
=head3 Application bundling for Windows
tbd. Use L<NSIS|http://nsis.sourceforge.net/Main_Page> or
L<InstallJammer|http://www.installjammer.com/>.
=head3 Application bundling as DEB package
tbd. See L<Link|http://www.webupd8.org/2010/01/how-to-create-deb-package-ubuntu-debian.html>.
=head3 Application bundling as RPM package
tbd.
=head1 ROADMAP
One thing on the todo list is to create a full-duplex connection
between client and server so that the client can react on
server events directly. This may be implemented using the HTML5
WebSocket protocol. For now all communication is iniciated from
the client using AJAX calls.
=head1 SEE ALSO
This module actually stands a bit on its own with its approach.
XUL modules exist though - XUL::Gui, XUL::Node and a few more.
=head1 AUTHOR
Tom Kirchner, E<lt>tom@tomkirchner.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2011 by Tom Kirchner
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut
( run in 1.689 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )