ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Mozilla-Plugin/Plugin.pm
Revision: 1.10
Committed: Mon Mar 5 12:05:56 2001 UTC (23 years, 2 months ago) by root
Branch: MAIN
Changes since 1.9: +133 -53 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.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 root 1.2 sorry...
12    
13 root 1.1 =over 4
14    
15     =cut
16    
17     package Mozilla::Plugin;
18    
19     use base Exporter;
20 root 1.3 use Storable;
21 root 1.1 #use XSLoader;
22    
23 root 1.3 $VERSION = 0.01;
24 root 1.1 @EXPORT = qw();
25    
26     #XSLoader::load __PACKAGE__, $VERSION;
27    
28 root 1.6 my $interface; # Mozilla::Plugin::xxx (design weakness)
29    
30 root 1.8 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 root 1.1 my $data;
59    
60 root 1.8 sub BIAS() { -2147483647 } # ugliest hack ever seen
61 root 1.3
62 root 1.9 sub snd_cmd {
63     $data = pack "NN", 0, ord($_[-1]);
64 root 1.1 }
65    
66 root 1.9 sub snd_ptr {
67     $data .= $_[-1];
68 root 1.3 }
69    
70 root 1.9 sub snd_u32 {
71     $data .= pack "N", $_[-1];
72 root 1.3 }
73    
74 root 1.9 sub snd_i32 {
75     $data .= pack "N", $_[-1] - BIAS;
76 root 1.1 }
77    
78 root 1.9 sub snd_blk {
79     $data .= pack "NA*", length($_[-1]), $_[-1];
80 root 1.1 }
81    
82 root 1.9 sub snd_snd {
83 root 1.1 substr ($data, 0, 4) = pack "N", length $data;
84 root 1.3 length ($data) == syswrite FD, $data;
85 root 1.2 }
86    
87 root 1.9 sub snd_dyn {
88     length ($_[-1]) == syswrite FD, $_[-1];
89 root 1.1 }
90    
91 root 1.9 sub rcv_cmd {
92 root 1.10 shift if ref $_[0];
93     my $cmd = shift;
94     my ($buf, $rcmd, $len);
95    
96     do {
97     4 == sysread FD, $buf, 4 or exit;
98     $len = unpack "N", $buf;
99     $len -= 4;
100     $len == sysread FD, $buf, $len or die;
101    
102     $data = substr $buf, 4;
103    
104     $rcmd = substr $buf, 3, 1;
105     if ($rcmd =~ /^[a-z]$/) {
106     die "rcv_cmd: sync error, expected '$cmd' but got '$rcmd'\n" if $cmd && $rcmd ne $cmd;
107     return $rcmd;
108     } else {
109     &_handle_event($rcmd);
110     }
111     } while ($cmd);
112 root 1.1 }
113    
114 root 1.9 sub rcv_ptr {
115 root 1.3 my $ptr = substr $data, 0, 8;
116     $data = substr $data, 8;
117     $ptr;
118     }
119    
120 root 1.9 sub rcv_u32 {
121 root 1.3 my $u32 = unpack "N", $data;
122     $data = substr $data, 4;
123     $u32;
124     }
125    
126 root 1.9 sub rcv_i32 {
127 root 1.3 my $i32 = BIAS + unpack "N", $data;
128 root 1.1 $data = substr $data, 4;
129     $i32;
130     }
131    
132 root 1.9 sub rcv_blk {
133 root 1.1 my $len = unpack "N", $data;
134     my $str = substr $data, 4, $len;
135     $data = substr $data, 4 + $len;
136     $str;
137     }
138    
139 root 1.9 sub rcv_dyn {
140     my $buf;
141     $_[-1] == sysread FD, $buf, $_[-1] or die "rcv_dyn: $!";
142     $buf;
143     }
144    
145 root 1.10 sub _handle_event($) {
146     my $cmd = shift;
147 root 1.1
148     if ($cmd eq "I") {
149 root 1.3 rcv_u32 == 1 or die "protocol version mismatch\n";
150 root 1.1 ($IFACE, $OSNAME, $OSVERS) = (rcv_blk, rcv_blk, rcv_blk);
151 root 1.3
152 root 1.8 } elsif ($cmd eq "+") { # New
153 root 1.1 my ($objid, $type, $mode, $save, $argc)
154 root 1.3 = (rcv_ptr, rcv_blk, rcv_u32, rcv_blk, rcv_u32);
155 root 1.1 my %args;
156 root 1.2 while ($argc--) {
157     my ($argn, $argv) = (rcv_blk, rcv_blk);
158     $args{$argn} = $argv;
159     }
160 root 1.1
161 root 1.6 $_OBJ{$objid} = $interface->new(
162 root 1.9 instance => $objid,
163     type => $type,
164     mode => $mode,
165     save => $save,
166     args => \%args,
167 root 1.6 );
168 root 1.1
169 root 1.8 } elsif ($cmd eq "-") { # Destroy
170 root 1.3 my $objid = rcv_ptr;
171     my $save = (delete $_OBJ{$objid})->save;
172 root 1.2 snd_cmd "-";
173 root 1.3 snd_u32 length $save;
174     snd_snd and snd_dyn $save;
175    
176 root 1.8 } elsif ($cmd eq "X") { # SetWindow
177 root 1.3 my $objid = rcv_ptr;
178     my %args = (
179 root 1.9 id => rcv_ptr,
180     x => rcv_i32,
181     y => rcv_i32,
182     w => rcv_i32,
183     h => rcv_i32,
184 root 1.3 );
185     if ($IFACE eq "UNIX") {
186 root 1.9 $args{id} = unpack "xxxxN", $args{id};
187 root 1.3 $args{ws_type} = rcv_i32;
188     $args{ws_depth} = rcv_u32;
189     }
190    
191 root 1.8 snd_cmd 'X';
192     snd_u32 $_OBJ{$objid}->set_window(\%args);
193     snd_snd;
194    
195     } elsif ($cmd eq "N") { # NewStream
196     my $obj = $_OBJ{+rcv_ptr};
197     my %args = (
198 root 1.9 instance => $obj,
199 root 1.8 mimetype => rcv_blk,
200     id => rcv_ptr,
201     url => rcv_blk,
202     end => rcv_u32,
203     lastmodified => rcv_u32,
204     notifydata => rcv_u32,
205     seekable => rcv_u32,
206 root 1.9 push_stream => 1,
207 root 1.8 );
208 root 1.10 my $str = $_OBJ{$args{id}} = new Mozilla::Stream::Receive \%args;
209 root 1.8
210     my ($stype, $err) = $obj->push_stream($str);
211    
212 root 1.9 snd_cmd 'N';
213 root 1.8 snd_u32 $err;
214     snd_u32 $stype || NP_NORMAL;
215     snd_snd;
216    
217     } elsif ($cmd eq "/") { # StreamAsFile
218     my $obj = $_OBJ{+rcv_ptr};
219     my $str = $_OBJ{+rcv_ptr};
220     my $path = rcv_blk;
221    
222     $obj->stream_as_file($obj, $stream, $path);
223    
224     } elsif ($cmd eq "R") { # WriteReady
225     my $obj = $_OBJ{+rcv_ptr};
226     my $str = $_OBJ{+rcv_ptr};
227    
228     snd_cmd 'R';
229     snd_u32 $obj->write_ready($obj, $str);
230     snd_snd;
231    
232     } elsif ($cmd eq "W") { # Write
233     my $obj = $_OBJ{+rcv_ptr};
234     my $str = $_OBJ{+rcv_ptr};
235     my $ofs = rcv_i32;
236     my $len = rcv_i32;
237     my $dta = rcv_dyn $len;
238    
239     snd_cmd 'W';
240     snd_i32 $obj->write($str, $ofs, $len, $dta);
241     snd_snd;
242    
243     } elsif ($cmd eq "D") { # DestroyStream
244     my $obj = $_OBJ{+rcv_ptr};
245     my $str = delete $_OBJ{+rcv_ptr};
246     my $why = rcv_u32;
247    
248     $obj->destroy_stream($obj, $str, $why);
249 root 1.3
250 root 1.1 } else {
251     die "unknown command '$cmd' received";
252     }
253     }
254    
255 root 1.10 =item my $fh = server_fh
256    
257     The design of this module is event-based. When the plug-in starts (there
258     is always just one interpreter) it spawns one perl interpreter which
259     will immediately go into a even loop. If you want to use your own event
260     loop (e.g. using the Gtk or Event modules) you need to register a file
261     input handler on the filehandle returned by C<server_fh> that calls
262     C<server_event> whenever there is input pending on C<server_fh>. This will
263     ensure proper operation of the plug-in.
264    
265     =item server_event
266    
267     Call this function whenever there is data available on the C<server_fh>. This function
268     might not return.
269    
270     Due to this design (flaw?), sharing of different toolkits using this
271     plug-in is difficult at best. Spawning a new perl interpreter for every
272     plug-in is also not very viable, so in the future one might be able to
273     specify a group on the embed statement (i.e. EMBED GROUP="gtk+").
274    
275     =cut
276    
277     sub server_fh { \*FD }
278    
279     sub server_event { rcv_cmd }
280    
281 root 1.1 sub mainloop {
282 root 1.2 server_event while 1;
283 root 1.1 }
284    
285 root 1.3 sub init {
286 root 1.6 $interface = shift;
287 root 1.5
288 root 1.6 open FD, "+<&=$_[0]"; binmode FD;
289 root 1.1
290 root 1.6 $interface->mainloop;
291 root 1.1 }
292    
293     sub new {
294 root 1.2 my $class = shift;
295 root 1.3 my $self = bless { @_ }, $class;
296     $self->{save} = $self->{save} ne ""
297     ? Storable::thaw $self->{save}
298     : {};
299     $self;
300 root 1.1 }
301    
302     sub set_window {
303 root 1.3 my $self = shift;
304     my $new = shift;
305 root 1.9
306     if ($self->{wininfo}) {
307     if ($self->{wininfo}{id} ne $new->{id}) {
308     $self->window_delete($self->{wininfo});
309     } elsif ($self->{wininfo}{w} != $new->{w}
310     or $self->{wininfo}{h} != $new->{h}) {
311     $self->window_resize($new->{id}, $new->{w}, $new->{h});
312 root 1.3 }
313 root 1.9 $self->{wininfo} = $new;
314 root 1.6 }
315    
316 root 1.9 unless ($self->{wininfo}) {
317     $self->{window} = $self->window_new($new) and $self->{wininfo} = $new;
318 root 1.3 }
319 root 1.8
320     ();
321 root 1.1 }
322    
323 root 1.10 sub window_new { () }
324 root 1.3 sub window_resize {}
325 root 1.6
326     sub window_delete {
327     my $self = shift;
328 root 1.9 delete $self->{wininfo};
329 root 1.6 delete $self->{window};
330     }
331 root 1.3
332 root 1.1 sub save {
333 root 1.6 my $self = shift;
334     $self->set_window(undef);
335 root 1.10 $self->destroy;
336 root 1.6 Storable::nfreeze $self->{save};
337 root 1.1 }
338    
339 root 1.8 sub destroy {}
340     sub DESTROY {}
341     sub write_ready { 0xfffff }
342     sub push_stream {}
343     sub stream_as_file {}
344     sub destroy_stream {}
345    
346     sub write {
347     my ($self) = shift;
348     shift->write(@_);
349 root 1.9 }
350    
351 root 1.10 =item ($error, $stream) = new_stream $mimetype, $target
352    
353     Requests the creation of a new data stream produced by the plug-in and
354     consumed by the browser.
355    
356     =cut
357    
358     sub new_stream {
359     my ($self, $type, $target) = @_;
360     my ($error, $stream);
361    
362     snd_cmd 'n';
363     snd_blk $mimetype;
364     snd_blk $target;
365     if (snd_snd) {
366     rcv_cmd 'n';
367     $error = rcv_u32;
368     unless ($error) {
369     $stream = new Mozilla::Stream::Send (
370     instance => $self,
371     mimetype => $type,
372     id => rcv_ptr,
373     url => $target,
374     );
375     }
376     }
377     ($error, $stream);
378     }
379    
380     =item $error = $obj->get_url $url, $target
381 root 1.9
382 root 1.10 =cut
383    
384     sub get_url {
385     my ($self, $url, $target) = @_;
386     }
387    
388     sub Mozilla::Stream::new {
389 root 1.9 bless $_[1], $_[0];
390     }
391    
392 root 1.10 sub Mozilla::Stream::destroy {
393     my $str = shift;
394     my $error = shift;
395     unless ($str->{destroyed}) {
396     $str->{destroyed}++;
397    
398     my $obj = $str->{instance};
399     snd_cmd 'd';
400     snd_ptr $obj->{id};
401     snd_ptr $str->{id};
402     snd_u32 $error || NPERR_NO_ERROR;
403     snd_snd;
404     }
405     }
406    
407     *Mozilla::Stream::DESTROY = \&Mozilla::Stream::destroy;
408    
409     BEGIN {
410     @Mozilla::Stream::Receive::ISA = Mozilla::Stream;
411     }
412    
413     sub Mozilla::Stream::Receive::write {
414 root 1.9 # ...
415     }
416    
417 root 1.10 BEGIN {
418     @Mozilla::Stream::Send::ISA = Mozilla::Stream;
419     }
420    
421     =item $bytes = $stream->write($data)
422    
423     =cut
424    
425     sub Mozilla::Stream::Send::write {
426     my $str = shift;
427     my $obj = $self->{instance};
428    
429     snd_cmd 'w';
430     snd_ptr $obj->{id};
431     snd_ptr $str->{id};
432     snd_u32 length $_[0];
433     if (snd_snd) {
434     if (snd_dyn $_[0]) {
435     rcv_cmd 'w';
436     return rcv_i32 ();
437     }
438     }
439     return 0;
440 root 1.1 }
441    
442     1;
443    
444     =back
445    
446     =head1 BUGS
447    
448     =head1 SEE ALSO
449    
450     L<PApp>.
451    
452     =head1 AUTHOR
453    
454     Marc Lehmann <pcg@goof.com>
455     http://www.goof.com/pcg/marc/
456    
457     =cut
458