* ./ChangeLog: updated.
[vlc.git] / mozilla / vlcplugin.c
1 /*****************************************************************************
2  * vlcplugin.c: a VideoLAN Client plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: vlcplugin.c,v 1.1 2002/07/04 18:11:57 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>
28 #include <string.h>
29
30 /* Mozilla stuff */
31 #include <plugin/npapi.h>
32
33 /* X11 stuff */
34 #include <X11/Xlib.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/StringDefs.h>
37
38 /* vlc stuff */
39 #include <vlc/vlc.h>
40
41 #include "vlcplugin.h"
42
43 /*******************************************************************************
44  * Unix-only declarations
45  ******************************************************************************/
46 static void Redraw( Widget w, XtPointer closure, XEvent *event );
47
48 /*******************************************************************************
49  * UNIX-only API calls
50  ******************************************************************************/
51 char* NPP_GetMIMEDescription( void )
52 {
53     return( PLUGIN_MIMETYPES );
54 }
55
56 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
57 {
58     NPError err = NPERR_NO_ERROR;
59     if (variable == NPPVpluginNameString)
60         *((char **)value) = PLUGIN_NAME;
61     else if (variable == NPPVpluginDescriptionString)
62         *((char **)value) = PLUGIN_DESCRIPTION;
63     else
64         err = NPERR_GENERIC_ERROR;
65
66     return err;
67 }
68
69 /*******************************************************************************
70  * General Plug-in Calls
71  ******************************************************************************/
72 NPError NPP_Initialize( void )
73 {
74     fprintf(stderr, "NPP_Initialize\n");
75     return NPERR_NO_ERROR;
76 }
77
78 jref NPP_GetJavaClass( void )
79 {
80     return NULL;                /* Java disabled */
81 }
82
83 void NPP_Shutdown( void )
84 {
85     /* Java disabled */
86 }
87
88 NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
89                  char* argn[], char* argv[], NPSavedData* saved )
90 {
91     NPError result = NPERR_NO_ERROR;
92     PluginInstance* This;
93     int i_ret;
94     int i;
95
96     char *ppsz_foo[] =
97     {
98         "vlc",
99         //"--plugin-path", "/home/sam/videolan/vlc_MAIN/plugins",
100         "--vout", "xvideo,x11,dummy",
101         "--intf", "dummy",
102         "--noaudio",
103         //"-v"
104     };
105
106     fprintf(stderr, "NPP_New\n");
107
108     if (instance == NULL)
109         return NPERR_INVALID_INSTANCE_ERROR;
110         
111     instance->pdata = NPN_MemAlloc(sizeof(PluginInstance));
112     
113     This = (PluginInstance*) instance->pdata;
114
115     if (This == NULL)
116         return NPERR_OUT_OF_MEMORY_ERROR;
117
118     {
119         /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */
120         This->fMode = mode;
121         This->fWindow = NULL;
122
123         This->window = 0;
124     }
125
126     This->p_vlc = vlc_create();
127     if( This->p_vlc == NULL )
128     {
129         return NPERR_GENERIC_ERROR;
130     }
131
132     i_ret = vlc_init( This->p_vlc, sizeof(ppsz_foo)/sizeof(char*), ppsz_foo );
133     if( i_ret )
134     {
135         vlc_destroy( This->p_vlc );
136         This->p_vlc = NULL;
137         return NPERR_GENERIC_ERROR;
138     }
139
140     i_ret = vlc_run( This->p_vlc );
141     if( i_ret )
142     {
143         vlc_end( This->p_vlc );
144         vlc_destroy( This->p_vlc );
145         This->p_vlc = NULL;
146         return NPERR_GENERIC_ERROR;
147     }
148
149     This->b_stream = 0;
150     This->psz_target = NULL;
151
152     for( i = 0; i < argc ; i++ )
153     {
154         fprintf(stderr, "arg %i: '%s' = '%s'\n", i, argn[i], argv[i]);
155         if(!strcmp(argn[i],"target"))
156         {
157             fprintf(stderr, "target specified: %s\n", argv[i]);
158             This->psz_target = strdup( argv[i] );
159         }
160         else
161         {
162             //__config_PutPsz( This->psz_target, argn[i], argv[i] );
163         }
164     }
165
166     return result;
167 }
168
169 NPError NPP_Destroy( NPP instance, NPSavedData** save )
170 {
171     PluginInstance* This;
172
173     fprintf(stderr, "NPP_Destroy\n");
174
175     if (instance == NULL)
176         return NPERR_INVALID_INSTANCE_ERROR;
177
178     This = (PluginInstance*) instance->pdata;
179
180     if( This->p_vlc != NULL )
181     {
182         vlc_stop( This->p_vlc );
183         vlc_end( This->p_vlc );
184         vlc_destroy( This->p_vlc );
185         This->p_vlc = NULL;
186     }
187
188     if( This->psz_target )
189     {
190         free( This->psz_target );
191         This->psz_target = NULL;
192     }
193
194     if (This != NULL) {
195         NPN_MemFree(instance->pdata);
196         instance->pdata = NULL;
197     }
198
199     return NPERR_NO_ERROR;
200 }
201
202 NPError NPP_SetWindow( NPP instance, NPWindow* window )
203 {
204     NPError result = NPERR_NO_ERROR;
205     PluginInstance* This;
206
207     fprintf(stderr, "NPP_SetWindow\n");
208
209     if (instance == NULL)
210         return NPERR_INVALID_INSTANCE_ERROR;
211
212     This = (PluginInstance*) instance->pdata;
213
214     __config_PutInt( This->p_vlc, "x11-drawable", window->window );
215     __config_PutInt( This->p_vlc, "xvideo-drawable", window->window );
216     /*
217      * PLUGIN DEVELOPERS:
218      *  Before setting window to point to the
219      *  new window, you may wish to compare the new window
220      *  info to the previous window (if any) to note window
221      *  size changes, etc.
222      */
223     
224     {
225         Widget netscape_widget;
226
227         This->window = (Window) window->window;
228         This->x = window->x;
229         This->y = window->y;
230         This->width = window->width;
231         This->height = window->height;
232         This->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
233
234         netscape_widget = XtWindowToWidget(This->display, This->window);
235         XtAddEventHandler(netscape_widget, ExposureMask, FALSE, (XtEventHandler)Redraw, This);
236         Redraw(netscape_widget, (XtPointer)This, NULL);
237     }
238
239     This->fWindow = window;
240
241 #if 1
242     if( !This->b_stream )
243     {
244         This->b_stream = 1;
245         if( This->psz_target )
246         {
247             vlc_add_target( This->p_vlc, This->psz_target, PLAYLIST_APPEND, PLAYLIST_END );
248                     /* We loop, dude */
249             vlc_add_target( This->p_vlc, "vlc:loop", PLAYLIST_APPEND, PLAYLIST_END );
250         }
251     }
252 #endif
253
254     return result;
255 }
256
257
258 NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream, 
259                        NPBool seekable, uint16 *stype )
260 {
261     PluginInstance* This;
262
263     fprintf(stderr, "NPP_NewStream - FILE mode !!\n");
264
265     if (instance == NULL)
266         return NPERR_INVALID_INSTANCE_ERROR;
267
268     This = (PluginInstance*) instance->pdata;
269
270     /* We want a *filename* ! */
271     *stype = NP_ASFILE;
272
273 #if 0
274     if( This->b_stream == 0 )
275     {
276         This->psz_target = strdup( stream->url );
277         This->b_stream = 1;
278     }
279 #endif
280
281     return NPERR_NO_ERROR;
282 }
283
284
285 /* PLUGIN DEVELOPERS:
286  *      These next 2 functions are directly relevant in a plug-in which
287  *      handles the data in a streaming manner. If you want zero bytes
288  *      because no buffer space is YET available, return 0. As long as
289  *      the stream has not been written to the plugin, Navigator will
290  *      continue trying to send bytes.  If the plugin doesn't want them,
291  *      just return some large number from NPP_WriteReady(), and
292  *      ignore them in NPP_Write().  For a NP_ASFILE stream, they are
293  *      still called but can safely be ignored using this strategy.
294  */
295
296 int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
297                    * mode so we can take any size stream in our
298                    * write call (since we ignore it) */
299
300 #define SARASS_SIZE (1024*1024)
301
302 int32 NPP_WriteReady( NPP instance, NPStream *stream )
303 {
304     PluginInstance* This;
305
306     fprintf(stderr, "NPP_WriteReady\n");
307
308     if (instance != NULL)
309     {
310         This = (PluginInstance*) instance->pdata;
311         /* Muahahahahahahaha */
312         return STREAMBUFSIZE;
313         //return SARASS_SIZE;
314     }
315
316     /* Number of bytes ready to accept in NPP_Write() */
317     return STREAMBUFSIZE;
318     //return 0;
319 }
320
321
322 int32 NPP_Write( NPP instance, NPStream *stream, int32 offset,
323                  int32 len, void *buffer )
324 {
325     fprintf(stderr, "NPP_Write %i\n", len);
326
327     if (instance != NULL)
328     {
329         //PluginInstance* This = (PluginInstance*) instance->pdata;
330     }
331
332     return len;         /* The number of bytes accepted */
333 }
334
335
336 NPError NPP_DestroyStream( NPP instance, NPStream *stream, NPError reason )
337 {
338     PluginInstance* This;
339     fprintf(stderr, "NPP_DestroyStream\n");
340
341     if (instance == NULL)
342         return NPERR_INVALID_INSTANCE_ERROR;
343     This = (PluginInstance*) instance->pdata;
344
345     return NPERR_NO_ERROR;
346 }
347
348
349 void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* fname )
350 {
351     PluginInstance* This;
352     fprintf(stderr, "NPP_StreamAsFile\n");
353     if (instance != NULL)
354     {
355         This = (PluginInstance*) instance->pdata;
356         vlc_add_target( This->p_vlc, fname, PLAYLIST_APPEND, PLAYLIST_END );
357                 /* We loop, dude */
358         vlc_add_target( This->p_vlc, "vlc:loop", PLAYLIST_APPEND, PLAYLIST_END );
359     }
360 }
361
362
363 void NPP_Print( NPP instance, NPPrint* printInfo )
364 {
365     fprintf(stderr, "NPP_Print\n");
366
367     if(printInfo == NULL)
368         return;
369
370     if (instance != NULL) {
371         PluginInstance* This = (PluginInstance*) instance->pdata;
372     
373         if (printInfo->mode == NP_FULL) {
374             /*
375              * PLUGIN DEVELOPERS:
376              *  If your plugin would like to take over
377              *  printing completely when it is in full-screen mode,
378              *  set printInfo->pluginPrinted to TRUE and print your
379              *  plugin as you see fit.  If your plugin wants Netscape
380              *  to handle printing in this case, set
381              *  printInfo->pluginPrinted to FALSE (the default) and
382              *  do nothing.  If you do want to handle printing
383              *  yourself, printOne is true if the print button
384              *  (as opposed to the print menu) was clicked.
385              *  On the Macintosh, platformPrint is a THPrint; on
386              *  Windows, platformPrint is a structure
387              *  (defined in npapi.h) containing the printer name, port,
388              *  etc.
389              */
390
391             void* platformPrint =
392                 printInfo->print.fullPrint.platformPrint;
393             NPBool printOne =
394                 printInfo->print.fullPrint.printOne;
395             
396             /* Do the default*/
397             printInfo->print.fullPrint.pluginPrinted = FALSE;
398         }
399         else {  /* If not fullscreen, we must be embedded */
400             /*
401              * PLUGIN DEVELOPERS:
402              *  If your plugin is embedded, or is full-screen
403              *  but you returned false in pluginPrinted above, NPP_Print
404              *  will be called with mode == NP_EMBED.  The NPWindow
405              *  in the printInfo gives the location and dimensions of
406              *  the embedded plugin on the printed page.  On the
407              *  Macintosh, platformPrint is the printer port; on
408              *  Windows, platformPrint is the handle to the printing
409              *  device context.
410              */
411
412             NPWindow* printWindow =
413                 &(printInfo->print.embedPrint.window);
414             void* platformPrint =
415                 printInfo->print.embedPrint.platformPrint;
416         }
417     }
418 }
419
420 /*******************************************************************************
421 // NPP_URLNotify:
422 // Notifies the instance of the completion of a URL request. 
423 // 
424 // NPP_URLNotify is called when Netscape completes a NPN_GetURLNotify or
425 // NPN_PostURLNotify request, to inform the plug-in that the request,
426 // identified by url, has completed for the reason specified by reason. The most
427 // common reason code is NPRES_DONE, indicating simply that the request
428 // completed normally. Other possible reason codes are NPRES_USER_BREAK,
429 // indicating that the request was halted due to a user action (for example,
430 // clicking the "Stop" button), and NPRES_NETWORK_ERR, indicating that the
431 // request could not be completed (for example, because the URL could not be
432 // found). The complete list of reason codes is found in npapi.h. 
433 // 
434 // The parameter notifyData is the same plug-in-private value passed as an
435 // argument to the corresponding NPN_GetURLNotify or NPN_PostURLNotify
436 // call, and can be used by your plug-in to uniquely identify the request. 
437  ******************************************************************************/
438 void NPP_URLNotify( NPP instance, const char* url, NPReason reason,
439                     void* notifyData )
440 {
441 }
442
443 /*******************************************************************************
444  * UNIX-only methods
445  ******************************************************************************/
446 static void Redraw( Widget w, XtPointer closure, XEvent *event )
447 {
448     PluginInstance* This = (PluginInstance*)closure;
449     GC gc;
450     XGCValues gcv;
451     const char* text = "hello d00dZ, I'm in void Redraw()";
452
453     XtVaGetValues(w, XtNbackground, &gcv.background,
454                   XtNforeground, &gcv.foreground, 0);
455     gc = XCreateGC(This->display, This->window, 
456                    GCForeground|GCBackground, &gcv);
457     XDrawRectangle(This->display, This->window, gc, 
458                    0, 0, This->width-1, This->height-1);
459     XDrawString(This->display, This->window, gc, 
460                 This->width/2 - 100, This->height/2,
461                 text, strlen(text));
462     return;
463 }
464