ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Mozilla-Plugin/Plugin.pm
Revision: 1.9
Committed: Sun Mar 4 12:49:19 2001 UTC (23 years, 2 months ago) by root
Branch: MAIN
Changes since 1.8: +71 -44 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Mozilla::Plugin - embed perl into mozilla/netscape.
4
5 =head1 SYNOPSIS
6
7 use Mozilla::Plugin;
8
9 =head1 DESCRIPTION
10
11 sorry...
12
13 =over 4
14
15 =cut
16
17 package Mozilla::Plugin;
18
19 use base Exporter;
20 use Storable;
21 #use XSLoader;
22
23 $VERSION = 0.01;
24 @EXPORT = qw();
25
26 #XSLoader::load __PACKAGE__, $VERSION;
27
28 my $interface; # Mozilla::Plugin::xxx (design weakness)
29
30 sub NP_VERSION_MAJOR (){ 0 }
31 sub NP_VERSION_MINOR (){ 9 }
32 sub NP_EMBED (){ 1 }
33 sub NP_FULL (){ 2 }
34 sub NP_NORMAL (){ 1 }
35 sub NP_SEEK (){ 2 }
36 sub NP_ASFILE (){ 3 }
37 sub NP_ASFILEONLY (){ 4 }
38 sub NP_MAXREADY (){ 2147483647 }
39 sub NPERR_NO_ERROR (){ 0 }
40 sub NPERR_GENERIC_ERROR (){ 1 }
41 sub NPERR_INVALID_INSTANCE_ERROR (){ 2 }
42 sub NPERR_INVALID_FUNCTABLE_ERROR (){ 3 }
43 sub NPERR_MODULE_LOAD_FAILED_ERROR (){ 4 }
44 sub NPERR_OUT_OF_MEMORY_ERROR (){ 5 }
45 sub NPERR_INVALID_PLUGIN_ERROR (){ 6 }
46 sub NPERR_INVALID_PLUGIN_DIR_ERROR (){ 7 }
47 sub NPERR_INCOMPATIBLE_VERSION_ERROR (){ 8 }
48 sub NPERR_INVALID_PARAM (){ 9 }
49 sub NPERR_INVALID_URL (){ 10 }
50 sub NPERR_FILE_NOT_FOUND (){ 11 }
51 sub NPERR_NO_DATA (){ 12 }
52 sub NPERR_STREAM_NOT_SEEKABLE (){ 13 }
53 sub NPVERS_HAS_STREAMOUTPUT (){ 8 }
54 sub NPVERS_HAS_NOTIFICATION (){ 9 }
55 sub NPVERS_HAS_LIVECONNECT (){ 9 }
56 sub NPVERS_WIN16_HAS_LIVECONNECT (){ 10 }
57
58 my $data;
59
60 sub BIAS() { -2147483647 } # ugliest hack ever seen
61
62 sub snd_cmd {
63 $data = pack "NN", 0, ord($_[-1]);
64 }
65
66 sub snd_ptr {
67 $data .= $_[-1];
68 }
69
70 sub snd_u32 {
71 $data .= pack "N", $_[-1];
72 }
73
74 sub snd_i32 {
75 $data .= pack "N", $_[-1] - BIAS;
76 }
77
78 sub snd_blk {
79 $data .= pack "NA*", length($_[-1]), $_[-1];
80 }
81
82 sub snd_snd {
83 substr ($data, 0, 4) = pack "N", length $data;
84 length ($data) == syswrite FD, $data;
85 }
86
87 sub snd_dyn {
88 length ($_[-1]) == syswrite FD, $_[-1];
89 }
90
91 sub rcv_cmd {
92 my $buf;
93 4 == sysread FD, $buf, 4 or exit;
94 my $len = unpack "N", $buf;
95 $len -= 4;
96 $len == sysread FD, $buf, $len or die;
97
98 $data = substr $buf, 4;
99
100 substr $buf, 3, 1;
101 }
102
103 sub rcv_ptr {
104 my $ptr = substr $data, 0, 8;
105 $data = substr $data, 8;
106 printf "RCV_PTR(%s)\n", unpack "H*", $ptr;
107 $ptr;
108 }
109
110 sub rcv_u32 {
111 my $u32 = unpack "N", $data;
112 $data = substr $data, 4;
113 $u32;
114 }
115
116 sub rcv_i32 {
117 my $i32 = BIAS + unpack "N", $data;
118 $data = substr $data, 4;
119 $i32;
120 }
121
122 sub rcv_blk {
123 my $len = unpack "N", $data;
124 my $str = substr $data, 4, $len;
125 $data = substr $data, 4 + $len;
126 $str;
127 }
128
129 sub rcv_dyn {
130 my $buf;
131 $_[-1] == sysread FD, $buf, $_[-1] or die "rcv_dyn: $!";
132 $buf;
133 }
134
135 =item my $fh = server_fh
136
137 The design of this module is event-based. When the plug-in starts (there
138 is always just one interpreter) it spawns one perl interpreter which
139 will immediately go into a even loop. If you want to use your own event
140 loop (e.g. using the Gtk or Event modules) you need to register a file
141 input handler on the filehandle returned by C<server_fh> that calls
142 C<server_event> whenever there is input pending on C<server_fh>. This will
143 ensure proper operation of the plug-in.
144
145 =item server_event
146
147 Call this function whenever there is data available on the C<server_fh>. This function
148 might not return.
149
150 Due to this design (flaw?), sharing of different toolkits using this
151 plug-in is difficult at best. Spawning a new perl interpreter for every
152 plug-in is also not very viable, so in the future one might be able to
153 specify a group on the embed statement (i.e. EMBED GROUP="gtk+").
154
155 =cut
156
157 sub server_fh() { \*FD }
158
159 sub server_event() {
160 my $cmd = rcv_cmd;
161
162 warn "cmd<$cmd>\n";#d#
163
164 if ($cmd eq "I") {
165 rcv_u32 == 1 or die "protocol version mismatch\n";
166 ($IFACE, $OSNAME, $OSVERS) = (rcv_blk, rcv_blk, rcv_blk);
167
168 } elsif ($cmd eq "+") { # New
169 my ($objid, $type, $mode, $save, $argc)
170 = (rcv_ptr, rcv_blk, rcv_u32, rcv_blk, rcv_u32);
171 my %args;
172 while ($argc--) {
173 my ($argn, $argv) = (rcv_blk, rcv_blk);
174 $args{$argn} = $argv;
175 }
176
177 $_OBJ{$objid} = $interface->new(
178 instance => $objid,
179 type => $type,
180 mode => $mode,
181 save => $save,
182 args => \%args,
183 );
184
185 } elsif ($cmd eq "-") { # Destroy
186 my $objid = rcv_ptr;
187 my $save = (delete $_OBJ{$objid})->save;
188 snd_cmd "-";
189 snd_u32 length $save;
190 snd_snd and snd_dyn $save;
191
192 } elsif ($cmd eq "X") { # SetWindow
193 my $objid = rcv_ptr;
194 my %args = (
195 id => rcv_ptr,
196 x => rcv_i32,
197 y => rcv_i32,
198 w => rcv_i32,
199 h => rcv_i32,
200 );
201 if ($IFACE eq "UNIX") {
202 $args{id} = unpack "xxxxN", $args{id};
203 $args{ws_type} = rcv_i32;
204 $args{ws_depth} = rcv_u32;
205 }
206
207 snd_cmd 'X';
208 snd_u32 $_OBJ{$objid}->set_window(\%args);
209 snd_snd;
210
211 } elsif ($cmd eq "N") { # NewStream
212 my $obj = $_OBJ{+rcv_ptr};
213 my %args = (
214 instance => $obj,
215 mimetype => rcv_blk,
216 id => rcv_ptr,
217 url => rcv_blk,
218 end => rcv_u32,
219 lastmodified => rcv_u32,
220 notifydata => rcv_u32,
221 seekable => rcv_u32,
222 push_stream => 1,
223 );
224 my $str = $_OBJ{$args{id}} = new Mozilla::Stream \%args;
225
226 my ($stype, $err) = $obj->push_stream($str);
227
228 snd_cmd 'N';
229 snd_u32 $err;
230 snd_u32 $stype || NP_NORMAL;
231 snd_snd;
232
233 } elsif ($cmd eq "/") { # StreamAsFile
234 my $obj = $_OBJ{+rcv_ptr};
235 my $str = $_OBJ{+rcv_ptr};
236 my $path = rcv_blk;
237
238 $obj->stream_as_file($obj, $stream, $path);
239
240 } elsif ($cmd eq "R") { # WriteReady
241 my $obj = $_OBJ{+rcv_ptr};
242 my $str = $_OBJ{+rcv_ptr};
243
244 snd_cmd 'R';
245 snd_u32 $obj->write_ready($obj, $str);
246 snd_snd;
247
248 } elsif ($cmd eq "W") { # Write
249 my $obj = $_OBJ{+rcv_ptr};
250 my $str = $_OBJ{+rcv_ptr};
251 my $ofs = rcv_i32;
252 my $len = rcv_i32;
253 my $dta = rcv_dyn $len;
254
255 snd_cmd 'W';
256 snd_i32 $obj->write($str, $ofs, $len, $dta);
257 snd_snd;
258
259 } elsif ($cmd eq "D") { # DestroyStream
260 my $obj = $_OBJ{+rcv_ptr};
261 my $str = delete $_OBJ{+rcv_ptr};
262 my $why = rcv_u32;
263
264 $obj->destroy_stream($obj, $str, $why);
265
266 } else {
267 die "unknown command '$cmd' received";
268 }
269 }
270
271 sub mainloop {
272 server_event while 1;
273 }
274
275 sub init {
276 $interface = shift;
277
278 open FD, "+<&=$_[0]"; binmode FD;
279
280 $interface->mainloop;
281 }
282
283 sub new {
284 my $class = shift;
285 my $self = bless { @_ }, $class;
286 $self->{save} = $self->{save} ne ""
287 ? Storable::thaw $self->{save}
288 : {};
289 $self;
290 }
291
292 sub set_window {
293 my $self = shift;
294 my $new = shift;
295
296 if ($self->{wininfo}) {
297 if ($self->{wininfo}{id} ne $new->{id}) {
298 $self->window_delete($self->{wininfo});
299 } elsif ($self->{wininfo}{w} != $new->{w}
300 or $self->{wininfo}{h} != $new->{h}) {
301 $self->window_resize($new->{id}, $new->{w}, $new->{h});
302 }
303 $self->{wininfo} = $new;
304 }
305
306 unless ($self->{wininfo}) {
307 $self->{window} = $self->window_new($new) and $self->{wininfo} = $new;
308 }
309
310 ();
311 }
312
313 sub window_new {}
314 sub window_resize {}
315
316 sub window_delete {
317 my $self = shift;
318 delete $self->{wininfo};
319 delete $self->{window};
320 }
321
322 sub save {
323 my $self = shift;
324 $self->set_window(undef);
325 $self->{destroy};
326 Storable::nfreeze $self->{save};
327 }
328
329 sub destroy {}
330 sub DESTROY {}
331 sub write_ready { 0xfffff }
332 sub push_stream {}
333 sub stream_as_file {}
334 sub destroy_stream {}
335
336 sub write {
337 my ($self) = shift;
338 shift->write(@_);
339 }
340
341 package Mozilla::Stream;
342
343 sub new {
344 bless $_[1], $_[0];
345 }
346
347 sub write {
348 # ...
349 }
350
351 sub DESTROY {
352 my $str = $_[0];
353 warn "DESTROY stream";
354
355 my $obj = $str->{instance};
356 $obj->snd_cmd('d');
357 $obj->snd_ptr($obj);
358 $obj->snd_ptr($str);
359 $obj->snd_snd;
360 }
361
362 1;
363
364 =back
365
366 =head1 BUGS
367
368 =head1 SEE ALSO
369
370 L<PApp>.
371
372 =head1 AUTHOR
373
374 Marc Lehmann <pcg@goof.com>
375 http://www.goof.com/pcg/marc/
376
377 =cut
378