* mozilla/vlcshell.cpp: free() requires <stdlib.h>.
[vlc.git] / mozilla / vlcshell.cpp
1 /*****************************************************************************
2  * vlcshell.cpp: a VLC plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: vlcshell.cpp,v 1.13 2003/07/09 13:52:22 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 /* XXX: disable VLC here */
25 #define USE_LIBVLC 1
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 /* vlc stuff */
35 #ifdef USE_LIBVLC
36 #   include <vlc/vlc.h>
37 #endif
38
39 /* Mozilla stuff */
40 #include <npapi.h>
41
42 #ifdef XP_WIN
43     /* Windows stuff */
44 #endif
45
46 #ifdef XP_UNIX
47     /* X11 stuff */
48 #   include <X11/Xlib.h>
49 #   include <X11/Intrinsic.h>
50 #   include <X11/StringDefs.h>
51 #endif
52
53 #ifdef XP_MAC
54     /* Mac OS X stuff */
55 #   include <QuickDraw.h>
56 #endif
57
58 #include "vlcpeer.h"
59 #include "vlcplugin.h"
60
61 #if USE_LIBVLC
62 #   define WINDOW_TEXT "(no picture)"
63 #else
64 #   define WINDOW_TEXT "(no libvlc)"
65 #endif
66
67 /*****************************************************************************
68  * Unix-only declarations
69 ******************************************************************************/
70 #ifdef XP_UNIX
71 #   define VOUT_PLUGINS "xvideo,x11,dummy"
72 #   define AOUT_PLUGINS "oss,dummy"
73
74 static void Redraw( Widget w, XtPointer closure, XEvent *event );
75 #endif
76
77 /*****************************************************************************
78  * Windows-only declarations
79  *****************************************************************************/
80 #ifdef XP_WIN
81 #   define VOUT_PLUGINS "directx,dummy"
82 #   define AOUT_PLUGINS "none" /* "directx,waveout,dummy" */
83
84 HINSTANCE g_hDllInstance = NULL;
85
86 BOOL WINAPI
87 DllMain( HINSTANCE  hinstDLL,                   // handle of DLL module
88                     DWORD  fdwReason,       // reason for calling function
89                     LPVOID  lpvReserved)
90 {
91     switch (fdwReason)
92     {
93         case DLL_PROCESS_ATTACH:
94             g_hDllInstance = hinstDLL;
95             break;
96         case DLL_THREAD_ATTACH:
97         case DLL_PROCESS_DETACH:
98         case DLL_THREAD_DETACH:
99             break;
100     }
101     return TRUE;
102 }
103
104 LRESULT CALLBACK Manage( HWND, UINT, WPARAM, LPARAM );
105 #endif
106
107 /******************************************************************************
108  * UNIX-only API calls
109  *****************************************************************************/
110 char * NPP_GetMIMEDescription( void )
111 {
112     return PLUGIN_MIMETYPES;
113 }
114
115 NPError NPP_GetValue( NPP instance, NPPVariable variable, void *value )
116 {
117     static nsIID nsid = VLCINTF_IID;
118     static char psz_desc[1000];
119
120     switch( variable )
121     {
122         case NPPVpluginNameString:
123             *((char **)value) = PLUGIN_NAME;
124             return NPERR_NO_ERROR;
125
126         case NPPVpluginDescriptionString:
127 #if USE_LIBVLC
128             snprintf( psz_desc, 1000-1, PLUGIN_DESCRIPTION, VLC_Version() );
129 #else
130             snprintf( psz_desc, 1000-1, PLUGIN_DESCRIPTION, "(disabled)" );
131 #endif
132             psz_desc[1000-1] = 0;
133             *((char **)value) = psz_desc;
134             return NPERR_NO_ERROR;
135
136         default:
137             /* go on... */
138             break;
139     }
140
141     if( instance == NULL )
142     {
143         return NPERR_INVALID_INSTANCE_ERROR;
144     }
145
146     VlcPlugin* p_plugin = (VlcPlugin*) instance->pdata;
147
148     switch( variable )
149     {
150         case NPPVpluginScriptableInstance:
151             *(nsISupports**)value = p_plugin->GetPeer();
152             if( *(nsISupports**)value == NULL )
153             {
154                 return NPERR_OUT_OF_MEMORY_ERROR;
155             }
156             break;
157
158         case NPPVpluginScriptableIID:
159             *(nsIID**)value = (nsIID*)NPN_MemAlloc( sizeof(nsIID) );
160             if( *(nsIID**)value == NULL )
161             {
162                 return NPERR_OUT_OF_MEMORY_ERROR;
163             }
164             **(nsIID**)value = nsid;
165             break;
166
167         default:
168             return NPERR_GENERIC_ERROR;
169     }
170
171     return NPERR_NO_ERROR;
172 }
173
174 /******************************************************************************
175  * Mac-only API calls
176  *****************************************************************************/
177 #ifdef XP_MAC
178 int16 NPP_HandleEvent( NPP instance, void * event )
179 {
180     if( instance == NULL )
181     {
182         return false;
183     }
184
185     Boolean eventHandled = false;
186
187 #if 0
188     TPlugin *pPlugin = (TPlugin*)instance->pdata;
189     if( pPlugin != NULL && event != NULL )
190     {
191         eventHandled = pPlugin->HandleEvent( *(EventRecord*)event );
192     }
193 #endif
194
195     return eventHandled;
196 }
197 #endif
198
199 /******************************************************************************
200  * General Plug-in Calls
201  *****************************************************************************/
202 NPError NPP_Initialize( void )
203 {
204     return NPERR_NO_ERROR;
205 }
206
207 jref NPP_GetJavaClass( void )
208 {
209     return NULL;
210 }
211
212 void NPP_Shutdown( void )
213 {
214     ;
215 }
216
217 NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
218                  char* argn[], char* argv[], NPSavedData* saved )
219 {
220     int i;
221 #if USE_LIBVLC
222     vlc_value_t value;
223     int i_ret;
224
225     char *ppsz_foo[] =
226     {
227         "vlc"
228         /*, "--plugin-path", "/home/sam/videolan/vlc_MAIN/plugins"*/
229     };
230 #endif
231
232     if( instance == NULL )
233     {
234         return NPERR_INVALID_INSTANCE_ERROR;
235     }
236
237     VlcPlugin * p_plugin = new VlcPlugin( instance );
238
239     if( p_plugin == NULL )
240     {
241         return NPERR_OUT_OF_MEMORY_ERROR;
242     }
243
244     instance->pdata = p_plugin;
245
246 #ifdef XP_WIN
247     p_plugin->p_hwnd = NULL;
248     p_plugin->pf_wndproc = NULL;
249 #endif
250
251 #ifdef XP_UNIX
252     p_plugin->window = 0;
253     p_plugin->p_display = NULL;
254 #endif
255
256     p_plugin->p_npwin = NULL;
257     p_plugin->i_npmode = mode;
258     p_plugin->i_width = 0;
259     p_plugin->i_height = 0;
260
261 #if USE_LIBVLC
262     p_plugin->i_vlc = VLC_Create();
263     if( p_plugin->i_vlc < 0 )
264     {
265         p_plugin->i_vlc = 0;
266         delete p_plugin;
267         p_plugin = NULL;
268         return NPERR_GENERIC_ERROR;
269     }
270
271     i_ret = VLC_Init( p_plugin->i_vlc, sizeof(ppsz_foo)/sizeof(char*), ppsz_foo );
272     if( i_ret )
273     {
274         VLC_Destroy( p_plugin->i_vlc );
275         p_plugin->i_vlc = 0;
276         delete p_plugin;
277         p_plugin = NULL;
278         return NPERR_GENERIC_ERROR;
279     }
280
281     value.psz_string = "dummy";
282     VLC_Set( p_plugin->i_vlc, "conf::intf", value );
283     value.psz_string = VOUT_PLUGINS;
284     VLC_Set( p_plugin->i_vlc, "conf::vout", value );
285     value.psz_string = AOUT_PLUGINS;
286     VLC_Set( p_plugin->i_vlc, "conf::aout", value );
287
288 #else
289     p_plugin->i_vlc = 1;
290
291 #endif /* USE_LIBVLC */
292
293     p_plugin->b_stream = VLC_FALSE;
294     p_plugin->b_autoplay = VLC_FALSE;
295     p_plugin->psz_target = NULL;
296
297     for( i = 0; i < argc ; i++ )
298     {
299         if( !strcmp( argn[i], "target" ) )
300         {
301             p_plugin->psz_target = argv[i];
302         }
303         else if( !strcmp( argn[i], "autoplay" ) )
304         {
305             if( !strcmp( argv[i], "yes" ) )
306             {
307                 p_plugin->b_autoplay = 1;
308             }
309         }
310         else if( !strcmp( argn[i], "autostart" ) )
311         {
312             if( !strcmp( argv[i], "1" ) || !strcmp( argv[i], "true" ) )
313             {
314                 p_plugin->b_autoplay = 1;
315             }
316         }
317         else if( !strcmp( argn[i], "filename" ) )
318         {
319             p_plugin->psz_target = argv[i];
320         }
321         else if( !strcmp( argn[i], "src" ) )
322         {
323             p_plugin->psz_target = argv[i];
324         }
325
326 #if USE_LIBVLC
327         else if( !strcmp( argn[i], "loop" ) )
328         {
329             if( !strcmp( argv[i], "yes" ) )
330             {
331                 value.b_bool = VLC_TRUE;
332                 VLC_Set( p_plugin->i_vlc, "conf::loop", value );
333             }
334         }
335 #endif
336     }
337
338     if( p_plugin->psz_target )
339     {
340         p_plugin->psz_target = strdup( p_plugin->psz_target );
341     }
342
343     return NPERR_NO_ERROR;
344 }
345
346 NPError NPP_Destroy( NPP instance, NPSavedData** save )
347 {
348     if( instance == NULL )
349     {
350         return NPERR_INVALID_INSTANCE_ERROR;
351     }
352
353     VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata;
354
355     if( p_plugin != NULL )
356     {
357         if( p_plugin->i_vlc )
358         {
359 #if USE_LIBVLC
360             VLC_Stop( p_plugin->i_vlc );
361             VLC_Destroy( p_plugin->i_vlc );
362 #endif
363             p_plugin->i_vlc = 0;
364         }
365
366         if( p_plugin->psz_target )
367         {
368             free( p_plugin->psz_target );
369             p_plugin->psz_target = NULL;
370         }
371
372         delete p_plugin;
373     }
374
375     instance->pdata = NULL;
376
377     return NPERR_NO_ERROR;
378 }
379
380 NPError NPP_SetWindow( NPP instance, NPWindow* window )
381 {
382     if( instance == NULL )
383     {
384         return NPERR_INVALID_INSTANCE_ERROR;
385     }
386
387     VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata;
388
389     /* Write the window ID for vlc */
390 #if USE_LIBVLC
391     vlc_value_t value;
392
393     /* FIXME: this cast sucks */
394     value.i_int = (int) (ptrdiff_t) (void *) window->window;
395     VLC_Set( p_plugin->i_vlc, "drawable", value );
396 #endif
397
398     /*
399      * PLUGIN DEVELOPERS:
400      *  Before setting window to point to the
401      *  new window, you may wish to compare the new window
402      *  info to the previous window (if any) to note window
403      *  size changes, etc.
404      */
405
406 #ifdef XP_WIN
407     if( !window || !window->window )
408     {
409         /* Window was destroyed. Invalidate everything. */
410         if( p_plugin->p_npwin )
411         {
412             SetWindowLong( p_plugin->p_hwnd, GWL_WNDPROC,
413                            (LONG)p_plugin->pf_wndproc );
414             p_plugin->pf_wndproc = NULL;
415             p_plugin->p_hwnd = NULL;
416         }
417
418         p_plugin->p_npwin = window;
419         return NPERR_NO_ERROR;
420     }
421
422     if( p_plugin->p_npwin )
423     {
424         if( p_plugin->p_hwnd == (HWND)window->window )
425         {
426             /* Same window, but something may have changed. First we
427              * update the plugin structure, then we redraw the window */
428             InvalidateRect( p_plugin->p_hwnd, NULL, TRUE );
429             p_plugin->i_width = window->width;
430             p_plugin->i_height = window->height;
431             p_plugin->p_npwin = window;
432             UpdateWindow( p_plugin->p_hwnd );
433             return NPERR_NO_ERROR;
434         }
435
436         /* Window has changed. Destroy the one we have, and go
437          * on as if it was a real initialization. */
438         SetWindowLong( p_plugin->p_hwnd, GWL_WNDPROC,
439                        (LONG)p_plugin->pf_wndproc );
440         p_plugin->pf_wndproc = NULL;
441         p_plugin->p_hwnd = NULL;
442     }
443
444     p_plugin->pf_wndproc = (WNDPROC)SetWindowLong( (HWND)window->window,
445                                                    GWL_WNDPROC, (LONG)Manage );
446     p_plugin->p_hwnd = (HWND)window->window;
447     SetProp( p_plugin->p_hwnd, "w00t", (HANDLE)p_plugin );
448     InvalidateRect( p_plugin->p_hwnd, NULL, TRUE );
449     UpdateWindow( p_plugin->p_hwnd );
450 #endif
451
452 #ifdef XP_UNIX
453     p_plugin->window = (Window) window->window;
454     p_plugin->p_display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
455
456     Widget w = XtWindowToWidget( p_plugin->p_display, p_plugin->window );
457     XtAddEventHandler( w, ExposureMask, FALSE,
458                        (XtEventHandler)Redraw, p_plugin );
459     Redraw( w, (XtPointer)p_plugin, NULL );
460 #endif
461
462     p_plugin->p_npwin = window;
463
464     p_plugin->i_width = window->width;
465     p_plugin->i_height = window->height;
466
467     if( !p_plugin->b_stream )
468     {
469         int i_mode = PLAYLIST_APPEND;
470
471         if( p_plugin->b_autoplay )
472         {
473             i_mode |= PLAYLIST_GO;
474         }
475
476         if( p_plugin->psz_target )
477         {
478 #if USE_LIBVLC
479             VLC_AddTarget( p_plugin->i_vlc, p_plugin->psz_target,
480                            i_mode, PLAYLIST_END );
481 #endif
482             p_plugin->b_stream = VLC_TRUE;
483         }
484     }
485
486     return NPERR_NO_ERROR;
487 }
488
489 NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream,
490                        NPBool seekable, uint16 *stype )
491 {
492     if( instance == NULL )
493     {
494         return NPERR_INVALID_INSTANCE_ERROR;
495     }
496
497 #if 0
498     VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata;
499 #endif
500
501     /* fprintf(stderr, "NPP_NewStream - FILE mode !!\n"); */
502
503     /* We want a *filename* ! */
504     *stype = NP_ASFILE;
505
506 #if 0
507     if( !p_plugin->b_stream )
508     {
509         p_plugin->psz_target = strdup( stream->url );
510         p_plugin->b_stream = VLC_TRUE;
511     }
512 #endif
513
514     return NPERR_NO_ERROR;
515 }
516
517 int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
518                    * mode so we can take any size stream in our
519                    * write call (since we ignore it) */
520
521 #define SARASS_SIZE (1024*1024)
522
523 int32 NPP_WriteReady( NPP instance, NPStream *stream )
524 {
525     VlcPlugin* p_plugin;
526
527     /* fprintf(stderr, "NPP_WriteReady\n"); */
528
529     if (instance != NULL)
530     {
531         p_plugin = (VlcPlugin*) instance->pdata;
532         /* Muahahahahahahaha */
533         return STREAMBUFSIZE;
534         /*return SARASS_SIZE;*/
535     }
536
537     /* Number of bytes ready to accept in NPP_Write() */
538     return STREAMBUFSIZE;
539     /*return 0;*/
540 }
541
542
543 int32 NPP_Write( NPP instance, NPStream *stream, int32 offset,
544                  int32 len, void *buffer )
545 {
546     /* fprintf(stderr, "NPP_Write %i\n", (int)len); */
547
548     if( instance != NULL )
549     {
550         /*VlcPlugin* p_plugin = (VlcPlugin*) instance->pdata;*/
551     }
552
553     return len;         /* The number of bytes accepted */
554 }
555
556
557 NPError NPP_DestroyStream( NPP instance, NPStream *stream, NPError reason )
558 {
559     if( instance == NULL )
560     {
561         return NPERR_INVALID_INSTANCE_ERROR;
562     }
563
564     return NPERR_NO_ERROR;
565 }
566
567
568 void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* fname )
569 {
570     if( instance == NULL )
571     {
572         return;
573     }
574
575     /* fprintf(stderr, "NPP_StreamAsFile %s\n", fname); */
576
577 #if USE_LIBVLC
578     VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata;
579
580     VLC_AddTarget( p_plugin->i_vlc, fname,
581                    PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
582 #endif
583 }
584
585
586 void NPP_URLNotify( NPP instance, const char* url,
587                     NPReason reason, void* notifyData )
588 {
589     /***** Insert NPP_URLNotify code here *****\
590     PluginInstance* p_plugin;
591     if (instance != NULL)
592         p_plugin = (PluginInstance*) instance->pdata;
593     \*********************************************/
594 }
595
596
597 void NPP_Print( NPP instance, NPPrint* printInfo )
598 {
599     if( printInfo == NULL )
600     {
601         return;
602     }
603
604     if( instance != NULL )
605     {
606         /***** Insert NPP_Print code here *****\
607         PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
608         \**************************************/
609
610         if( printInfo->mode == NP_FULL )
611         {
612             /*
613              * PLUGIN DEVELOPERS:
614              *  If your plugin would like to take over
615              *  printing completely when it is in full-screen mode,
616              *  set printInfo->pluginPrinted to TRUE and print your
617              *  plugin as you see fit.  If your plugin wants Netscape
618              *  to handle printing in this case, set
619              *  printInfo->pluginPrinted to FALSE (the default) and
620              *  do nothing.  If you do want to handle printing
621              *  yourself, printOne is true if the print button
622              *  (as opposed to the print menu) was clicked.
623              *  On the Macintosh, platformPrint is a THPrint; on
624              *  Windows, platformPrint is a structure
625              *  (defined in npapi.h) containing the printer name, port,
626              *  etc.
627              */
628
629             /***** Insert NPP_Print code here *****\
630             void* platformPrint =
631                 printInfo->print.fullPrint.platformPrint;
632             NPBool printOne =
633                 printInfo->print.fullPrint.printOne;
634             \**************************************/
635
636             /* Do the default*/
637             printInfo->print.fullPrint.pluginPrinted = FALSE;
638         }
639         else
640         {
641             /* If not fullscreen, we must be embedded */
642             /*
643              * PLUGIN DEVELOPERS:
644              *  If your plugin is embedded, or is full-screen
645              *  but you returned false in pluginPrinted above, NPP_Print
646              *  will be called with mode == NP_EMBED.  The NPWindow
647              *  in the printInfo gives the location and dimensions of
648              *  the embedded plugin on the printed page.  On the
649              *  Macintosh, platformPrint is the printer port; on
650              *  Windows, platformPrint is the handle to the printing
651              *  device context.
652              */
653
654             /***** Insert NPP_Print code here *****\
655             NPWindow* printWindow =
656                 &(printInfo->print.embedPrint.window);
657             void* platformPrint =
658                 printInfo->print.embedPrint.platformPrint;
659             \**************************************/
660         }
661     }
662 }
663
664 /******************************************************************************
665  * Windows-only methods
666  *****************************************************************************/
667 #ifdef XP_WIN
668 LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar )
669 {
670     VlcPlugin* p_plugin = (VlcPlugin*) GetProp( p_hwnd, "w00t" );
671
672     switch( i_msg )
673     {
674 #if !USE_LIBVLC
675         case WM_PAINT:
676         {
677             PAINTSTRUCT paintstruct;
678             HDC hdc;
679             RECT rect;
680
681             hdc = BeginPaint( p_hwnd, &paintstruct );
682
683             GetClientRect( p_hwnd, &rect );
684             FillRect( hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH) );
685             TextOut( hdc, p_plugin->i_width / 2 - 40, p_plugin->i_height / 2,
686                      WINDOW_TEXT, strlen(WINDOW_TEXT) );
687
688             EndPaint( p_hwnd, &paintstruct );
689             break;
690         }
691 #endif
692         default:
693             p_plugin->pf_wndproc( p_hwnd, i_msg, wpar, lpar );
694             break;
695     }
696     return 0;
697 }
698 #endif
699
700 /******************************************************************************
701  * UNIX-only methods
702  *****************************************************************************/
703 #ifdef XP_UNIX
704 static void Redraw( Widget w, XtPointer closure, XEvent *event )
705 {
706     VlcPlugin* p_plugin = (VlcPlugin*)closure;
707     GC gc;
708     XGCValues gcv;
709
710     gcv.foreground = BlackPixel( p_plugin->p_display, 0 );
711     gc = XCreateGC( p_plugin->p_display, p_plugin->window, GCForeground, &gcv );
712
713     XFillRectangle( p_plugin->p_display, p_plugin->window, gc,
714                     0, 0, p_plugin->i_width, p_plugin->i_height );
715
716     gcv.foreground = WhitePixel( p_plugin->p_display, 0 );
717     XChangeGC( p_plugin->p_display, gc, GCForeground, &gcv );
718
719     XDrawString( p_plugin->p_display, p_plugin->window, gc,
720                  p_plugin->i_width / 2 - 40, p_plugin->i_height / 2,
721                  WINDOW_TEXT, strlen(WINDOW_TEXT) );
722
723     XFreeGC( p_plugin->p_display, gc );
724 }
725 #endif
726