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