line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::XUL; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
5154422
|
use 5.010000; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
41
|
|
4
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
33
|
|
5
|
1
|
|
|
1
|
|
29
|
use warnings; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
42
|
|
6
|
1
|
|
|
1
|
|
1084
|
use Directory::Scratch::Structured qw(create_structured_tree); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use File::Copy::Recursive qw(fcopy dircopy); |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Data::Dumper::Concise; |
10
|
|
|
|
|
|
|
use App::XUL::XML; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
require Exporter; |
13
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
14
|
|
|
|
|
|
|
our @EXPORT = qw(AUTOLOAD); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
17
|
|
|
|
|
|
|
our $AUTOLOAD; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our $Singleton; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub AUTOLOAD |
24
|
|
|
|
|
|
|
{ |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
$App::XUL::XML::AUTOLOAD = $AUTOLOAD; |
27
|
|
|
|
|
|
|
return App::XUL::XML::AUTOLOAD(@_); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new |
33
|
|
|
|
|
|
|
{ |
34
|
|
|
|
|
|
|
my ($class, @args) = @_; |
35
|
|
|
|
|
|
|
my $self = bless {}, $class; |
36
|
|
|
|
|
|
|
$Singleton = $self; |
37
|
|
|
|
|
|
|
return $self->init(@args); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub init |
41
|
|
|
|
|
|
|
{ |
42
|
|
|
|
|
|
|
my ($self, %opts) = @_; |
43
|
|
|
|
|
|
|
$self->{'name'} = $opts{'name'} || do { die "Error: no app name given - new(name => <string>)\n" }; |
44
|
|
|
|
|
|
|
$self->{'windows'} = []; |
45
|
|
|
|
|
|
|
$self->{'bindings'} = {}; |
46
|
|
|
|
|
|
|
return $self |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub bind |
50
|
|
|
|
|
|
|
{ |
51
|
|
|
|
|
|
|
my ($id, $event, $coderef) = @_; |
52
|
|
|
|
|
|
|
$Singleton->{'bindings'}->{$id.':'.$event} = $coderef; |
53
|
|
|
|
|
|
|
return $Singleton; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub add |
57
|
|
|
|
|
|
|
{ |
58
|
|
|
|
|
|
|
my ($self, $window_xml) = @_; |
59
|
|
|
|
|
|
|
die "Error: add() only accepts a single window tag as first argument\n" |
60
|
|
|
|
|
|
|
if $window_xml !~ /^<window/; |
61
|
|
|
|
|
|
|
push @{$self->{'windows'}}, $window_xml; |
62
|
|
|
|
|
|
|
return $self; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub bundle |
66
|
|
|
|
|
|
|
{ |
67
|
|
|
|
|
|
|
my ($self, %opts) = @_; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
my $os = $opts{'os'} || die "Error: no os given - bundle(os => <string>)\n"; |
70
|
|
|
|
|
|
|
my $path = $opts{'path'} || die "Error: no path given - bundle(path => <string>)\n"; |
71
|
|
|
|
|
|
|
my $utilspath = $opts{'utilspath'} || die "Error: no utils path given - bundle(utilspath => <string>)\n"; |
72
|
|
|
|
|
|
|
$self->{'debug'} = $opts{'debug'} || 0; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
if ($os eq 'chrome') { |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
my $name = $self->{'name'}; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
my $tmpdir = create_structured_tree( |
83
|
|
|
|
|
|
|
$name => { |
84
|
|
|
|
|
|
|
'start_macosx.pl' => [$self->_get_file_startpl('chrome','macosx')], |
85
|
|
|
|
|
|
|
'start_win.pl' => [$self->_get_file_startpl('chrome','win')], |
86
|
|
|
|
|
|
|
'start_linux.pl' => [$self->_get_file_startpl('chrome','linux')], |
87
|
|
|
|
|
|
|
'chrome.manifest' => ['manifest chrome/chrome.manifest'."\n"], |
88
|
|
|
|
|
|
|
'application.ini' => [$self->_get_file_macosx_appini()], |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
'chrome' => { |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
'chrome.manifest' => [$self->_get_file_macosx_chromemanifest()], |
93
|
|
|
|
|
|
|
'content' => { |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
$self->_get_file_macosx_xulfiles(), |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
}, |
99
|
|
|
|
|
|
|
}, |
100
|
|
|
|
|
|
|
'defaults' => { |
101
|
|
|
|
|
|
|
'preferences' => { |
102
|
|
|
|
|
|
|
'prefs.js' => [$self->_get_file_macosx_prefs()], |
103
|
|
|
|
|
|
|
}, |
104
|
|
|
|
|
|
|
}, |
105
|
|
|
|
|
|
|
'perl' => { |
106
|
|
|
|
|
|
|
'server' => { |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
}, |
109
|
|
|
|
|
|
|
'modules' => { |
110
|
|
|
|
|
|
|
'Eventhandlers.pm' => [$self->_get_file_macosx_eventhandlers()], |
111
|
|
|
|
|
|
|
'App' => { |
112
|
|
|
|
|
|
|
'XUL' => { |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
}, |
116
|
|
|
|
|
|
|
}, |
117
|
|
|
|
|
|
|
}, |
118
|
|
|
|
|
|
|
}, |
119
|
|
|
|
|
|
|
'extensions' => {}, |
120
|
|
|
|
|
|
|
'updates' => { |
121
|
|
|
|
|
|
|
'0' => {}, |
122
|
|
|
|
|
|
|
}, |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
fcopy($utilspath.'/AppXUL.js', |
129
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'/chrome/content/AppXUL.js'); |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
fcopy($utilspath.'/server.pl', |
132
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'/perl/server/server.pl'); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
fcopy($utilspath.'/../lib/App/XUL/XML.pm', |
135
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'/perl/modules/App/XUL/XML.pm'); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
fcopy($utilspath.'/../lib/App/XUL/Object.pm', |
138
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'/perl/modules/App/XUL/Object.pm'); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
chmod(0755, $tmpdir->base().'/'.$name.'/start_macosx.pl'); |
142
|
|
|
|
|
|
|
chmod(0755, $tmpdir->base().'/'.$name.'/start_win.pl'); |
143
|
|
|
|
|
|
|
chmod(0755, $tmpdir->base().'/'.$name.'/start_linux.pl'); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
rename($tmpdir->base().'/'.$name, $path); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
elsif ($os eq 'macosx') { |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my $name = $self->{'name'}; |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
my $tmpdir = create_structured_tree( |
155
|
|
|
|
|
|
|
$name.'.app' => { |
156
|
|
|
|
|
|
|
'Contents' => { |
157
|
|
|
|
|
|
|
'Info.plist' => [$self->_get_file_maxosx_infoplist()], |
158
|
|
|
|
|
|
|
'Frameworks' => { |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
}, |
161
|
|
|
|
|
|
|
'MacOS' => { |
162
|
|
|
|
|
|
|
'start.pl' => [$self->_get_file_startpl('macosx')], |
163
|
|
|
|
|
|
|
}, |
164
|
|
|
|
|
|
|
'Resources' => { |
165
|
|
|
|
|
|
|
'chrome.manifest' => ['manifest chrome/chrome.manifest'."\n"], |
166
|
|
|
|
|
|
|
'application.ini' => [$self->_get_file_macosx_appini()], |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
'chrome' => { |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
'chrome.manifest' => [$self->_get_file_macosx_chromemanifest()], |
171
|
|
|
|
|
|
|
'content' => { |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
$self->_get_file_macosx_xulfiles(), |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
}, |
177
|
|
|
|
|
|
|
}, |
178
|
|
|
|
|
|
|
'defaults' => { |
179
|
|
|
|
|
|
|
'preferences' => { |
180
|
|
|
|
|
|
|
'prefs.js' => [$self->_get_file_macosx_prefs()], |
181
|
|
|
|
|
|
|
}, |
182
|
|
|
|
|
|
|
}, |
183
|
|
|
|
|
|
|
'perl' => { |
184
|
|
|
|
|
|
|
'server' => { |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
}, |
187
|
|
|
|
|
|
|
'modules' => { |
188
|
|
|
|
|
|
|
'Eventhandlers.pm' => [$self->_get_file_macosx_eventhandlers()], |
189
|
|
|
|
|
|
|
'App' => { |
190
|
|
|
|
|
|
|
'XUL' => { |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
}, |
194
|
|
|
|
|
|
|
}, |
195
|
|
|
|
|
|
|
}, |
196
|
|
|
|
|
|
|
}, |
197
|
|
|
|
|
|
|
'extensions' => {}, |
198
|
|
|
|
|
|
|
'updates' => { |
199
|
|
|
|
|
|
|
'0' => {}, |
200
|
|
|
|
|
|
|
}, |
201
|
|
|
|
|
|
|
}, |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
); |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
die "Error: no XUL.framework found in /Library/Frameworks - please install XUL framework from mozilla.org\n" |
208
|
|
|
|
|
|
|
unless -d '/Library/Frameworks/XUL.framework'; |
209
|
|
|
|
|
|
|
dircopy('/Library/Frameworks/XUL.framework', |
210
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Frameworks/XUL.framework'); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
fcopy($utilspath.'/Appicon.icns', |
213
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Resources/'.$name.'.icns'); |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
fcopy($utilspath.'/AppXUL.js', |
216
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Resources/chrome/content/AppXUL.js'); |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
fcopy($utilspath.'/server.pl', |
222
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/server/server.pl'); |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
fcopy($utilspath.'/../lib/App/XUL/XML.pm', |
225
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/modules/App/XUL/XML.pm'); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
fcopy($utilspath.'/../lib/App/XUL/Object.pm', |
228
|
|
|
|
|
|
|
$tmpdir->base().'/'.$name.'.app/Contents/Resources/perl/modules/App/XUL/Object.pm'); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
chmod(0755, $tmpdir->base().'/'.$name.'.app/Contents/MacOS/start.pl'); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
rename($tmpdir->base().'/'.$name.'.app', $path); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
else { |
237
|
|
|
|
|
|
|
die "Error: os '$os' not implemented yet\n"; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub _get_file_macosx_eventhandlers |
244
|
|
|
|
|
|
|
{ |
245
|
|
|
|
|
|
|
my ($self) = @_; |
246
|
|
|
|
|
|
|
my $eventhandlers = ''; |
247
|
|
|
|
|
|
|
foreach my $name (keys %{$self->{'bindings'}}) { |
248
|
|
|
|
|
|
|
$eventhandlers .= "'".$name."' => \n".Dumper($self->{'bindings'}->{$name}).",\n"; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
return |
251
|
|
|
|
|
|
|
'package Eventhandlers;'."\n". |
252
|
|
|
|
|
|
|
'use App::XUL::XML;'."\n". |
253
|
|
|
|
|
|
|
'$App::XUL::XML::RunInsideServer = 1;'."\n". |
254
|
|
|
|
|
|
|
'our $AUTOLOAD;'."\n". |
255
|
|
|
|
|
|
|
'sub AUTOLOAD {'."\n". |
256
|
|
|
|
|
|
|
' $App::XUL::XML::AUTOLOAD = $AUTOLOAD;'."\n". |
257
|
|
|
|
|
|
|
' return App::XUL::XML::AUTOLOAD(@_);'."\n". |
258
|
|
|
|
|
|
|
'}'."\n". |
259
|
|
|
|
|
|
|
'sub get {'."\n". |
260
|
|
|
|
|
|
|
' return {'."\n". |
261
|
|
|
|
|
|
|
$eventhandlers. |
262
|
|
|
|
|
|
|
' };'."\n". |
263
|
|
|
|
|
|
|
'}'."\n". |
264
|
|
|
|
|
|
|
'1;'."\n"; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub _get_file_macosx_prefs |
268
|
|
|
|
|
|
|
{ |
269
|
|
|
|
|
|
|
my ($self) = @_; |
270
|
|
|
|
|
|
|
return <<EOFSRC |
271
|
|
|
|
|
|
|
pref("toolkit.defaultChromeURI", "chrome://$self->{'name'}/content/main.xul"); |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
/* debugging prefs */ |
274
|
|
|
|
|
|
|
pref("browser.dom.window.dump.enabled", true); |
275
|
|
|
|
|
|
|
pref("javascript.options.showInConsole", true); |
276
|
|
|
|
|
|
|
pref("javascript.options.strict", true); |
277
|
|
|
|
|
|
|
pref("nglayout.debug.disable_xul_cache", true); |
278
|
|
|
|
|
|
|
pref("nglayout.debug.disable_xul_fastload", true); |
279
|
|
|
|
|
|
|
EOFSRC |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub _get_file_macosx_xulfiles |
283
|
|
|
|
|
|
|
{ |
284
|
|
|
|
|
|
|
my ($self) = @_; |
285
|
|
|
|
|
|
|
my @files = (); |
286
|
|
|
|
|
|
|
my $w = 0; |
287
|
|
|
|
|
|
|
foreach my $window_xml (@{$self->{'windows'}}) { |
288
|
|
|
|
|
|
|
my $xml = |
289
|
|
|
|
|
|
|
'<?xml version="1.0"?>'."\n". |
290
|
|
|
|
|
|
|
'<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>'."\n". |
291
|
|
|
|
|
|
|
$window_xml; |
292
|
|
|
|
|
|
|
push @files, ($w == 0 ? 'main' : 'sub'.$w).'.xul', [$xml]; |
293
|
|
|
|
|
|
|
$w++; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
return @files; |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub _get_file_macosx_chromemanifest |
309
|
|
|
|
|
|
|
{ |
310
|
|
|
|
|
|
|
my ($self) = @_; |
311
|
|
|
|
|
|
|
return 'content '.$self->{'name'}.' file:content/'."\n"; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub _get_file_macosx_appini |
315
|
|
|
|
|
|
|
{ |
316
|
|
|
|
|
|
|
my ($self) = @_; |
317
|
|
|
|
|
|
|
return <<EOFSRC |
318
|
|
|
|
|
|
|
[App] |
319
|
|
|
|
|
|
|
Version=1.0 |
320
|
|
|
|
|
|
|
Vendor=Me |
321
|
|
|
|
|
|
|
Name=$self->{'name'} |
322
|
|
|
|
|
|
|
BuildID=myid |
323
|
|
|
|
|
|
|
ID={generated id} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
[Gecko] |
326
|
|
|
|
|
|
|
MinVersion=1.8 |
327
|
|
|
|
|
|
|
MaxVersion=2.* |
328
|
|
|
|
|
|
|
EOFSRC |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
sub _get_file_startpl |
332
|
|
|
|
|
|
|
{ |
333
|
|
|
|
|
|
|
my ($self, $os, $type) = @_; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
if ($os eq 'chrome') { |
336
|
|
|
|
|
|
|
my $xulrunnerpath = { |
337
|
|
|
|
|
|
|
macosx => '/Library/Frameworks/XUL.framework/xulrunner-bin', |
338
|
|
|
|
|
|
|
win => 'c:\Program Files\xulrunner\xulrunner', |
339
|
|
|
|
|
|
|
linux => 'xulrunner', |
340
|
|
|
|
|
|
|
}; |
341
|
|
|
|
|
|
|
return |
342
|
|
|
|
|
|
|
'#!/usr/bin/perl -w'."\n". |
343
|
|
|
|
|
|
|
q{use strict; |
344
|
|
|
|
|
|
|
use Cwd 'abs_path'; |
345
|
|
|
|
|
|
|
my $path = abs_path($0); |
346
|
|
|
|
|
|
|
$path =~ s/\/start\_[a-z]+.pl$//; |
347
|
|
|
|
|
|
|
system( |
348
|
|
|
|
|
|
|
'"'.$path."/perl/server/server.pl".'" '. |
349
|
|
|
|
|
|
|
'"'.$path."/perl/modules/".'" 3000 &' |
350
|
|
|
|
|
|
|
); |
351
|
|
|
|
|
|
|
exec( |
352
|
|
|
|
|
|
|
"}.$xulrunnerpath->{$type}.q{", |
353
|
|
|
|
|
|
|
"-app", $path."/application.ini",}. |
354
|
|
|
|
|
|
|
($self->{'debug'} ? '"-jsconsole"' : ''). |
355
|
|
|
|
|
|
|
');'."\n"; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
elsif ($os eq 'macosx') { |
358
|
|
|
|
|
|
|
return |
359
|
|
|
|
|
|
|
'#!/usr/bin/perl -w'."\n". |
360
|
|
|
|
|
|
|
q{use strict; |
361
|
|
|
|
|
|
|
use Cwd 'abs_path'; |
362
|
|
|
|
|
|
|
my $path = abs_path($0); |
363
|
|
|
|
|
|
|
$path =~ s/\/MacOS\/[^\/]+//; |
364
|
|
|
|
|
|
|
system( |
365
|
|
|
|
|
|
|
'"'.$path."/Resources/perl/server/server.pl".'" '. |
366
|
|
|
|
|
|
|
'"'.$path."/Resources/perl/modules/".'" 3000 &' |
367
|
|
|
|
|
|
|
); |
368
|
|
|
|
|
|
|
exec( |
369
|
|
|
|
|
|
|
$path."/Frameworks/XUL.framework/xulrunner-bin", |
370
|
|
|
|
|
|
|
"-app", $path."/Resources/application.ini",}. |
371
|
|
|
|
|
|
|
($self->{'debug'} ? '"-jsconsole"' : ''). |
372
|
|
|
|
|
|
|
');'."\n"; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
else { |
375
|
|
|
|
|
|
|
return ''; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub _get_file_maxosx_infoplist |
380
|
|
|
|
|
|
|
{ |
381
|
|
|
|
|
|
|
my ($self) = @_; |
382
|
|
|
|
|
|
|
return <<EOFSRC |
383
|
|
|
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
384
|
|
|
|
|
|
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
385
|
|
|
|
|
|
|
<plist version="1.0"> |
386
|
|
|
|
|
|
|
<dict> |
387
|
|
|
|
|
|
|
<key>CFBundleDevelopmentRegion</key> |
388
|
|
|
|
|
|
|
<string>English</string> |
389
|
|
|
|
|
|
|
<key>CFBundleExecutable</key> |
390
|
|
|
|
|
|
|
<string>start.pl</string> |
391
|
|
|
|
|
|
|
<key>CFBundleGetInfoString</key> |
392
|
|
|
|
|
|
|
<string>XULExplorer 1.0a1pre, © 2007-2008 Contributors</string> |
393
|
|
|
|
|
|
|
<key>CFBundleIconFile</key> |
394
|
|
|
|
|
|
|
<string>$self->{'name'}</string> |
395
|
|
|
|
|
|
|
<key>CFBundleIdentifier</key> |
396
|
|
|
|
|
|
|
<string>org.mozilla.mccoy</string> |
397
|
|
|
|
|
|
|
<key>CFBundleInfoDictionaryVersion</key> |
398
|
|
|
|
|
|
|
<string>6.0</string> |
399
|
|
|
|
|
|
|
<key>CFBundleName</key> |
400
|
|
|
|
|
|
|
<string>$self->{'name'}</string> |
401
|
|
|
|
|
|
|
<key>CFBundlePackageType</key> |
402
|
|
|
|
|
|
|
<string>APPL</string> |
403
|
|
|
|
|
|
|
<key>CFBundleShortVersionString</key> |
404
|
|
|
|
|
|
|
<string>1.0a1pre</string> |
405
|
|
|
|
|
|
|
<key>CFBundleSignature</key> |
406
|
|
|
|
|
|
|
<string>MOZB</string> |
407
|
|
|
|
|
|
|
<key>CFBundleVersion</key> |
408
|
|
|
|
|
|
|
<string>1.0a1pre</string> |
409
|
|
|
|
|
|
|
<key>NSAppleScriptEnabled</key> |
410
|
|
|
|
|
|
|
<true/> |
411
|
|
|
|
|
|
|
</dict> |
412
|
|
|
|
|
|
|
</plist> |
413
|
|
|
|
|
|
|
EOFSRC |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
1; |
417
|
|
|
|
|
|
|
__END__ |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head1 NAME |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
App::XUL - Perl extension for creating deployable platform-independent |
422
|
|
|
|
|
|
|
standalone desktop applications based on XUL and XULRunner. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=for html <span style="color:red">WARNING: PRE-ALPHA - DON'T USE FOR PRODUCTION!</span> |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=head1 SYNOPSIS |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
use App::XUL; |
429
|
|
|
|
|
|
|
my $app = App::XUL->new(name => 'MyApp'); |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
$app->add( |
432
|
|
|
|
|
|
|
Window(id => 'main', |
433
|
|
|
|
|
|
|
Div(id => 'container', 'style' => 'background:black', |
434
|
|
|
|
|
|
|
Button(label => 'click', oncommand => sub { |
435
|
|
|
|
|
|
|
ID('container')->style('background:red'); |
436
|
|
|
|
|
|
|
}), |
437
|
|
|
|
|
|
|
), |
438
|
|
|
|
|
|
|
), |
439
|
|
|
|
|
|
|
); |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
$app->bundle(path => '/path/to/myapp.app', os => 'macosx'); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
XUL (+ XULRunner) makes it easy to create applications based |
444
|
|
|
|
|
|
|
on XML, CSS and JavaScript. App::XUL tries to simplify this |
445
|
|
|
|
|
|
|
even more by exchanging XML and JavaScript with Perl and |
446
|
|
|
|
|
|
|
providing an easy way to create deployable applications for the |
447
|
|
|
|
|
|
|
platforms XULRunner exists for. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 WHY XUL/XULRUNNER |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
XUL provides a set of powerful user widgets that look good |
452
|
|
|
|
|
|
|
and work as expected. They can be created with minimal effort |
453
|
|
|
|
|
|
|
and their appearance can be manipulated using CSS. |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
XUL is based on B<web technologies like XML, CSS and JavaScript>. |
456
|
|
|
|
|
|
|
So anyone who is able to use these is able to create cool |
457
|
|
|
|
|
|
|
desktop applications. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Here is the homepage of the L<XUL|https://developer.mozilla.org/En/XUL> |
460
|
|
|
|
|
|
|
and L<XULRunner|https://developer.mozilla.org/en/xulrunner> projects at Mozilla. |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=head1 DESCRIPTION |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head2 new() - Creating an application |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
The constructor new() is used to create a new application |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
my $app = App::XUL->new(name => 'MyApp'); |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head3 Options |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head4 name => I<string> |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
The name of the application. Later also used as the application executable's name. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head2 add() - Add a window to an application |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
add() adds a window to the XUL application. The XML for the window tag |
479
|
|
|
|
|
|
|
and its contained tags is created using Perl functions. The names of |
480
|
|
|
|
|
|
|
the Perl functions used to create the XML tags corresponds to the |
481
|
|
|
|
|
|
|
tagnames, just the first letter is uppercase: |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
$app->add( |
484
|
|
|
|
|
|
|
Window(id => 'main', |
485
|
|
|
|
|
|
|
Div(id => 'container', 'style' => 'background:black', |
486
|
|
|
|
|
|
|
Button(label => 'click', oncommand => sub { |
487
|
|
|
|
|
|
|
ID('container')->style('background:red'); |
488
|
|
|
|
|
|
|
}), |
489
|
|
|
|
|
|
|
); |
490
|
|
|
|
|
|
|
) |
491
|
|
|
|
|
|
|
); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
Keep in mind, that add will fail if the added tag is NOT a window tag. |
494
|
|
|
|
|
|
|
In XUL the root is always a window tag. |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
The first window beeing added is considered the main window and shown |
497
|
|
|
|
|
|
|
on startup. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head2 bundle() - Creating a deployable executable |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
$app->bundle(path => '/path/to/myapp.app', os => 'macosx'); |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
This will create a complete standalone XUL application containing all XML code. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Some general information about |
506
|
|
|
|
|
|
|
L<XUL application deployment|https://wiki.mozilla.org/XUL:XUL_Application_Packaging>. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head3 Options |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head4 path => I<string> |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=head4 os => I<string> |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
The systems currently supported are: |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=over 1 |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item chrome (native Chrome application) |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
This creates the usual directory for a XULRunner based application containing |
521
|
|
|
|
|
|
|
all needed files, except the XULRunner executable itself. A start Perl |
522
|
|
|
|
|
|
|
script for various operation systems is created as well, e.g. you can start |
523
|
|
|
|
|
|
|
the application by executing the start_macosx.pl file for Mac OS X. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Note for Linux users: You have to add the directory containing the |
526
|
|
|
|
|
|
|
xulrunner (or xulrunner-bin) executable to your $PATH variable or |
527
|
|
|
|
|
|
|
adjust the start_linux.pl script accordingly. This is due to the fact |
528
|
|
|
|
|
|
|
that XULRunner for Linux us currently in beta phase and can only |
529
|
|
|
|
|
|
|
be used by unpacking it into a local directory. |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=item macosx (Mac OS X) |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
L<Apple Documentation|http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1> |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=item win (Windows) |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
coming soon |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item deb or rpm (Ubuntu Linux) |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
tbd. Either a *.deb or *.rpm Paket. |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=back |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=head4 debug => I<1/0> |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
If debug is set to 1, a jsconsole is started together with the application |
548
|
|
|
|
|
|
|
which can be used to debugging messages. The default is debug = 0, so no |
549
|
|
|
|
|
|
|
jsconsole is started. |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head2 Creating interface components |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head2 Handling events |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Events can be handled by attaching an event handler to |
556
|
|
|
|
|
|
|
an interface component. Event handlers can either be written |
557
|
|
|
|
|
|
|
in Perl or in JavaScript. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Here is an example of a Perl event handler that reacts on |
560
|
|
|
|
|
|
|
the mouse click of a button: |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Button(label => 'click', oncommand => sub { |
563
|
|
|
|
|
|
|
# access environment and evtl. change it |
564
|
|
|
|
|
|
|
# ... |
565
|
|
|
|
|
|
|
}); |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
Here is a similar JavaScript event handler: |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Button(id => 'btn', label => 'click', oncommand => <<EOFJS); |
570
|
|
|
|
|
|
|
// here is some js code |
571
|
|
|
|
|
|
|
$('btn').update('Alrighty!'); |
572
|
|
|
|
|
|
|
EOFJS |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
JavaScript event handlers are executed faster than the Perl ones, |
575
|
|
|
|
|
|
|
due to the architecture (see below). |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=head2 Changing the environment from Perl |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
This refers to all activities within Perl event handlers that |
581
|
|
|
|
|
|
|
change the DOM of the XUL application. An example is the |
582
|
|
|
|
|
|
|
addition of another window, the insertion or update of a button |
583
|
|
|
|
|
|
|
label or the deletion of a style attribute etc. |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Some things are important here: |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=over 1 |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=item Changes happen on the server side first and are |
590
|
|
|
|
|
|
|
transferred to the client side (the XUL application) |
591
|
|
|
|
|
|
|
when the event handler terminates. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=item To manually transfer the latest changes to the client side |
594
|
|
|
|
|
|
|
use the PUSH() function. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=back |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=head4 Get (XML) element |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
The first step of changing the DOM is to get an element on which |
601
|
|
|
|
|
|
|
the changes are applied. The ID() function is used for that: |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
my $elem = ID('main'); |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
The ID() function only works WHILE the application is running. |
606
|
|
|
|
|
|
|
Any changes to the object returned by the ID() function are transferred |
607
|
|
|
|
|
|
|
immedietly (asynchronous) to the XUL application/client. |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head4 Get child (XML) elements |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
my $child1 = ID('main')->child(0); |
612
|
|
|
|
|
|
|
my $numchildren = ID('main')->numchildren(); |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
=head4 Create/insert/append (XML) elements |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
my $e = Div(id => 'container', 'style' => 'background:black', |
617
|
|
|
|
|
|
|
Button(label => 'click')); |
618
|
|
|
|
|
|
|
ID('main')->insert($e, 'end'); # end|start|... |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=head4 Edit (XML) element |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
ID('container')->style('background:red')->content(Span('Hello!')); |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head4 Delete/remove (XML) element |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
my $e = ID('container')->remove(); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head4 Call event handler on (XML) element |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
ID('container')->click(); |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head4 Register event handler on (XML) element |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
ID('container')->oncommand(sub { |
635
|
|
|
|
|
|
|
# do stuff here |
636
|
|
|
|
|
|
|
# ... |
637
|
|
|
|
|
|
|
}); |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head4 Un-register event handler on (XML) element |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
ID('container')->oncommand(undef); |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=head2 EXPORT |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
None by default. |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=head1 INTERNALS |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
This chapter is meant for informational purposes. Sometimes it is nessessary |
651
|
|
|
|
|
|
|
to know how things are implemented to decide, for example, if you should |
652
|
|
|
|
|
|
|
use a Perl or a JavaScript event handler etc. |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
App::XUL is client-server based. The client is the instance of |
655
|
|
|
|
|
|
|
XULRunner running and the server is a pure Perl based webserver |
656
|
|
|
|
|
|
|
that reacts on the events that are triggered by the XUL interface. |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=head3 Event handling |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
Essentially all events are dispatched from XUL as Ajax calls to the |
661
|
|
|
|
|
|
|
Perl webserver which handles the event, makes changes to the DOM etc. |
662
|
|
|
|
|
|
|
The changes are then transferred back to the XUL app where they |
663
|
|
|
|
|
|
|
are applied. |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Here is a rough workflow for event handling: |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=over 1 |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=item 1. Client registers an event (e.g. "mouseover", "click", "idle" etc.) |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=item 2. Client sends message to server (incl. parameters and environment) |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=item 3. Server calls appropriate Perl event handler subroutine |
674
|
|
|
|
|
|
|
(which may manipulate the environment) |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=item 4. Server sends the environment changes to the client as response |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=item 5. Client integrates environment changes |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=back |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head3 Communication protocol |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
The communication between XUL and server is based on a simple |
685
|
|
|
|
|
|
|
JSON based protocol. The following syntax definition tries to |
686
|
|
|
|
|
|
|
define the protocol. Everything in curly brackets is a JSON object, |
687
|
|
|
|
|
|
|
strings are quoted and non-terminals are written within "<",">" brackets. |
688
|
|
|
|
|
|
|
The pipe symbol ("|") means "OR". |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
<CLIENT-REQUEST> := <EVENT> |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
<SERVER-RESPONSE> := <ACTION> |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
<SERVER-REQUEST> := <ACTION> |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
<CLIENT-RESPONSE> := <STRING> |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
<EVENT> := { |
699
|
|
|
|
|
|
|
event: <EVENTNAME>, |
700
|
|
|
|
|
|
|
id: <ID> |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
<EVENTNAME> := |
704
|
|
|
|
|
|
|
"abort" | |
705
|
|
|
|
|
|
|
"blur" | |
706
|
|
|
|
|
|
|
"change" | |
707
|
|
|
|
|
|
|
"click" | |
708
|
|
|
|
|
|
|
"dblclick" | |
709
|
|
|
|
|
|
|
"dragdrop" | |
710
|
|
|
|
|
|
|
"error" | |
711
|
|
|
|
|
|
|
"focus" | |
712
|
|
|
|
|
|
|
"keydown" | |
713
|
|
|
|
|
|
|
"keypress" | |
714
|
|
|
|
|
|
|
"keyup" | |
715
|
|
|
|
|
|
|
"load" | |
716
|
|
|
|
|
|
|
"mousedown" | |
717
|
|
|
|
|
|
|
"mousemove" | |
718
|
|
|
|
|
|
|
"mouseout" | |
719
|
|
|
|
|
|
|
"mouseover" | |
720
|
|
|
|
|
|
|
"mouseup" | |
721
|
|
|
|
|
|
|
"move" | |
722
|
|
|
|
|
|
|
"reset" | |
723
|
|
|
|
|
|
|
"resize" | |
724
|
|
|
|
|
|
|
"select" | |
725
|
|
|
|
|
|
|
"submit" | |
726
|
|
|
|
|
|
|
"unload" |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
<ACTION> := |
729
|
|
|
|
|
|
|
<UPDATE> | |
730
|
|
|
|
|
|
|
<REMOVE> | |
731
|
|
|
|
|
|
|
<CREATE> | |
732
|
|
|
|
|
|
|
<QUIT> | |
733
|
|
|
|
|
|
|
<CHILD> | |
734
|
|
|
|
|
|
|
<NUMCHILDREN> | |
735
|
|
|
|
|
|
|
<INSERT> | |
736
|
|
|
|
|
|
|
<TRIGGER> | |
737
|
|
|
|
|
|
|
<REGISTER> | |
738
|
|
|
|
|
|
|
<UNREGISTER> | |
739
|
|
|
|
|
|
|
<SETATTR> | |
740
|
|
|
|
|
|
|
<GETATTR> |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
<UPDATE> := { |
743
|
|
|
|
|
|
|
action: "update", |
744
|
|
|
|
|
|
|
id: <ID>, |
745
|
|
|
|
|
|
|
attributes: <ATTRIBUTES>, |
746
|
|
|
|
|
|
|
subactions: [ <ACTION>, ... ] |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
<ATTRIBUTES> := {<NAME>: <STRING>, ...} |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
<REMOVE> := { |
752
|
|
|
|
|
|
|
action: "remove", |
753
|
|
|
|
|
|
|
id: <ID>, |
754
|
|
|
|
|
|
|
subactions: [ <ACTION>, ... ] |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
<CREATE> := { |
758
|
|
|
|
|
|
|
action: "create", |
759
|
|
|
|
|
|
|
parent: <ID>, |
760
|
|
|
|
|
|
|
attributes: <ATTRIBUTES>, |
761
|
|
|
|
|
|
|
content: <STRING>, |
762
|
|
|
|
|
|
|
subactions: [ <ACTION>, ... ] |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
<QUIT> := { |
766
|
|
|
|
|
|
|
action: "quit" |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
<CHILD> := { |
770
|
|
|
|
|
|
|
action: "child", |
771
|
|
|
|
|
|
|
id: <ID>, |
772
|
|
|
|
|
|
|
number: <NUMBER> |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
<NUMCHILDREN> := { |
776
|
|
|
|
|
|
|
action: "numchildren", |
777
|
|
|
|
|
|
|
id: <ID> |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
<INSERT> := { |
781
|
|
|
|
|
|
|
action: "insert", |
782
|
|
|
|
|
|
|
id: <ID>, |
783
|
|
|
|
|
|
|
position: <POSITION>, |
784
|
|
|
|
|
|
|
content: <STRING> |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
<TRIGGER> := { |
788
|
|
|
|
|
|
|
action: "trigger", |
789
|
|
|
|
|
|
|
id: <ID>, |
790
|
|
|
|
|
|
|
name: <STRING> |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
<REGISTER> := { |
794
|
|
|
|
|
|
|
action: "register", |
795
|
|
|
|
|
|
|
id: <ID>, |
796
|
|
|
|
|
|
|
name: <STRING>, |
797
|
|
|
|
|
|
|
callback: <STRING> |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
<UNREGISTER> := { |
801
|
|
|
|
|
|
|
action: "unregister", |
802
|
|
|
|
|
|
|
id: <ID>, |
803
|
|
|
|
|
|
|
name: <STRING> |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
<SETATTR> := { |
807
|
|
|
|
|
|
|
action: "setattr", |
808
|
|
|
|
|
|
|
id: <ID>, |
809
|
|
|
|
|
|
|
name: <STRING>, |
810
|
|
|
|
|
|
|
value: <STRING> |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
<GETATTR> := { |
814
|
|
|
|
|
|
|
action: "getattr", |
815
|
|
|
|
|
|
|
id: <ID>, |
816
|
|
|
|
|
|
|
name: <STRING> |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
Here are some examples of client requests: |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
{event:"click", id:"btn"} |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
Here are some examples of server responses: |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
{action:"update", id:"btn", attributes:{label:"Alrighty!"}} |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
{action:"remove", id:"btn"} |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
{action:"create", parent:"main", content:"<button .../>"} |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
=head3 Application bundling for Mac OS X |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Mac applications are simply directories whose names end with ".app" |
834
|
|
|
|
|
|
|
and have a certain structure and demand certain files to exist. |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
This is the structure of a XUL application wrapped inside a Mac application |
837
|
|
|
|
|
|
|
as created by App::XUL (files are blue, directories are black): |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=begin html |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
<pre> |
842
|
|
|
|
|
|
|
MyApp.app/ |
843
|
|
|
|
|
|
|
Contents/ |
844
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">Info.plist</span> |
845
|
|
|
|
|
|
|
Frameworks/ |
846
|
|
|
|
|
|
|
XUL.framework/ |
847
|
|
|
|
|
|
|
<i>The XUL Mac framework</i> |
848
|
|
|
|
|
|
|
MacOS |
849
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">start.pl</span> (Perl-Script) |
850
|
|
|
|
|
|
|
Resources |
851
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">application.ini</span> |
852
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">MyApp.icns</span> |
853
|
|
|
|
|
|
|
chrome/ |
854
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">chrome.manifest</span> |
855
|
|
|
|
|
|
|
content/ |
856
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">AppXUL.js</span> |
857
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">myapp.xul</span> |
858
|
|
|
|
|
|
|
defaults/ |
859
|
|
|
|
|
|
|
preferences/ |
860
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">prefs.js</span> |
861
|
|
|
|
|
|
|
perl/ |
862
|
|
|
|
|
|
|
server/ |
863
|
|
|
|
|
|
|
<span style="color:blue;font-weight:bold">server.pl</span> |
864
|
|
|
|
|
|
|
modules/ |
865
|
|
|
|
|
|
|
<i>All Perl modules the server depends on</i> |
866
|
|
|
|
|
|
|
extensions/ |
867
|
|
|
|
|
|
|
updates/ |
868
|
|
|
|
|
|
|
0/ |
869
|
|
|
|
|
|
|
</pre> |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=end html |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
The various files have specific functions. When the MyApp.app is |
874
|
|
|
|
|
|
|
clicked, the B<start.pl> program is executed which then starts the |
875
|
|
|
|
|
|
|
server and the client: |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
=over 1 |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
=item Info.plist |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
Required by Mac OS X. This is the place where certain basic information |
882
|
|
|
|
|
|
|
about the application is read by Mac OS X, before anything else is done. |
883
|
|
|
|
|
|
|
For example, here the start.pl program is defined as the entry point |
884
|
|
|
|
|
|
|
of the application. |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=item start.pl |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
First program to be executed. Starts server and client. |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=item application.ini |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
Setups the XUL application. Defines which *.xul files to load, |
893
|
|
|
|
|
|
|
name of application etc. |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
=item AppXUL.js |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
Defines all Javascript functions used by App::XUL to manage the |
898
|
|
|
|
|
|
|
communication with the server. |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=item myapp.xul |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
Defines the basic UI for the XUL application. |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=item prefs.js |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
Sets some preferences for the XUL application. |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=item server.pl |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
This starts the server. |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=back |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=head3 Application bundling for Windows |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
tbd. Use L<NSIS|http://nsis.sourceforge.net/Main_Page> or |
917
|
|
|
|
|
|
|
L<InstallJammer|http://www.installjammer.com/>. |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
=head3 Application bundling as DEB package |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
tbd. See L<Link|http://www.webupd8.org/2010/01/how-to-create-deb-package-ubuntu-debian.html>. |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
=head3 Application bundling as RPM package |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
tbd. |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
=head1 ROADMAP |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
One thing on the todo list is to create a full-duplex connection |
930
|
|
|
|
|
|
|
between client and server so that the client can react on |
931
|
|
|
|
|
|
|
server events directly. This may be implemented using the HTML5 |
932
|
|
|
|
|
|
|
WebSocket protocol. For now all communication is iniciated from |
933
|
|
|
|
|
|
|
the client using AJAX calls. |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
=head1 SEE ALSO |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
This module actually stands a bit on its own with its approach. |
938
|
|
|
|
|
|
|
XUL modules exist though - XUL::Gui, XUL::Node and a few more. |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
=head1 AUTHOR |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
Tom Kirchner, E<lt>tom@tomkirchner.comE<gt> |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
Copyright (C) 2011 by Tom Kirchner |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
949
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.10.0 or, |
950
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available. |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=cut |
954
|
|
|
|
|
|
|
|