]> git.sesse.net Git - vlc/blob - mozilla/vlcshell.cpp
6045ad4e18dd056b9420348dad9752a5bc632494
[vlc] / mozilla / vlcshell.cpp
1 /*****************************************************************************
2  * vlcshell.c: a VideoLAN Client plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: vlcshell.cpp,v 1.8 2003/01/28 16:57:28 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, "conf::x11-drawable", value );
363     VLC_Set( p_plugin->i_vlc, "conf::xvideo-drawable", value );
364
365     value.i_int = (int) (ptrdiff_t) (void *) window->window;
366     VLC_Set( p_plugin->i_vlc, "conf::directx-window", value );
367 #endif
368
369     /*
370      * PLUGIN DEVELOPERS:
371      *  Before setting window to point to the
372      *  new window, you may wish to compare the new window
373      *  info to the previous window (if any) to note window
374      *  size changes, etc.
375      */
376
377 #ifdef XP_WIN
378     if( !window || !window->window )
379     {
380         /* Window was destroyed. Invalidate everything. */
381         if( p_plugin->p_npwin )
382         {
383             SetWindowLong( p_plugin->p_hwnd, GWL_WNDPROC,
384                            (LONG)p_plugin->pf_wndproc );
385             p_plugin->pf_wndproc = NULL;
386             p_plugin->p_hwnd = NULL;
387         }
388
389         p_plugin->p_npwin = window;
390         return NPERR_NO_ERROR;
391     }
392
393     if( p_plugin->p_npwin )
394     {
395         if( p_plugin->p_hwnd == (HWND)window->window )
396         {
397             /* Same window, but something may have changed. First we
398              * update the plugin structure, then we redraw the window */
399             InvalidateRect( p_plugin->p_hwnd, NULL, TRUE );
400             p_plugin->i_width = window->width;
401             p_plugin->i_height = window->height;
402             p_plugin->p_npwin = window;
403             UpdateWindow( p_plugin->p_hwnd );
404             return NPERR_NO_ERROR;
405         }
406
407         /* Window has changed. Destroy the one we have, and go
408          * on as if it was a real initialization. */
409         SetWindowLong( p_plugin->p_hwnd, GWL_WNDPROC,
410                        (LONG)p_plugin->pf_wndproc );
411         p_plugin->pf_wndproc = NULL;
412         p_plugin->p_hwnd = NULL;
413     }
414
415     p_plugin->pf_wndproc = (WNDPROC)SetWindowLong( (HWND)window->window,
416                                                    GWL_WNDPROC, (LONG)Manage );
417     p_plugin->p_hwnd = (HWND)window->window;
418     SetProp( p_plugin->p_hwnd, "w00t", (HANDLE)p_plugin );
419     InvalidateRect( p_plugin->p_hwnd, NULL, TRUE );
420     UpdateWindow( p_plugin->p_hwnd );
421 #endif
422
423 #ifdef XP_UNIX
424     p_plugin->window = (Window) window->window;
425     p_plugin->p_display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
426
427     Widget w = XtWindowToWidget( p_plugin->p_display, p_plugin->window );
428     XtAddEventHandler( w, ExposureMask, FALSE,
429                        (XtEventHandler)Redraw, p_plugin );
430     Redraw( w, (XtPointer)p_plugin, NULL );
431 #endif
432
433     p_plugin->p_npwin = window;
434
435     p_plugin->i_width = window->width;
436     p_plugin->i_height = window->height;
437
438     if( !p_plugin->b_stream )
439     {
440         int i_mode = PLAYLIST_APPEND;
441
442         if( p_plugin->b_autoplay )
443         {
444             i_mode |= PLAYLIST_GO;
445         }
446
447         if( p_plugin->psz_target )
448         {
449 #if USE_LIBVLC
450             VLC_AddTarget( p_plugin->i_vlc, p_plugin->psz_target,
451                            i_mode, PLAYLIST_END );
452 #endif
453             p_plugin->b_stream = VLC_TRUE;
454         }
455     }
456
457     return NPERR_NO_ERROR;
458 }
459
460 NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream,
461                        NPBool seekable, uint16 *stype )
462 {
463     if( instance == NULL )
464     {
465         return NPERR_INVALID_INSTANCE_ERROR;
466     }
467
468 #if 0
469     VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata;
470 #endif
471
472     fprintf(stderr, "NPP_NewStream - FILE mode !!\n");
473
474     /* We want a *filename* ! */
475     *stype = NP_ASFILE;
476
477 #if 0
478     if( !p_plugin->b_stream )
479     {
480         p_plugin->psz_target = strdup( stream->url );
481         p_plugin->b_stream = VLC_TRUE;
482     }
483 #endif
484
485     return NPERR_NO_ERROR;
486 }
487
488 int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
489                    * mode so we can take any size stream in our
490                    * write call (since we ignore it) */
491
492 #define SARASS_SIZE (1024*1024)
493
494 int32 NPP_WriteReady( NPP instance, NPStream *stream )
495 {
496     VlcPlugin* p_plugin;
497
498     fprintf(stderr, "NPP_WriteReady\n");
499
500     if (instance != NULL)
501     {
502         p_plugin = (VlcPlugin*) instance->pdata;
503         /* Muahahahahahahaha */
504         return STREAMBUFSIZE;
505         /*return SARASS_SIZE;*/
506     }
507
508     /* Number of bytes ready to accept in NPP_Write() */
509     return STREAMBUFSIZE;
510     /*return 0;*/
511 }
512
513
514 int32 NPP_Write( NPP instance, NPStream *stream, int32 offset,
515                  int32 len, void *buffer )
516 {
517     fprintf(stderr, "NPP_Write %i\n", (int)len);
518
519     if( instance != NULL )
520     {
521         /*VlcPlugin* p_plugin = (VlcPlugin*) instance->pdata;*/
522     }
523
524     return len;         /* The number of bytes accepted */
525 }
526
527
528 NPError NPP_DestroyStream( NPP instance, NPStream *stream, NPError reason )
529 {
530     if( instance == NULL )
531     {
532         return NPERR_INVALID_INSTANCE_ERROR;
533     }
534
535     return NPERR_NO_ERROR;
536 }
537
538
539 void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* fname )
540 {
541     if( instance == NULL )
542     {
543         return;
544     }
545
546     fprintf(stderr, "NPP_StreamAsFile %s\n", fname);
547
548 #if USE_LIBVLC
549 /*    VlcPlugin* p_plugin = (VlcPlugin*)instance->pdata; */
550
551 /*    VLC_AddTarget( p_plugin->i_vlc, fname,
552       PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );*/
553 #endif
554 }
555
556
557 void NPP_URLNotify( NPP instance, const char* url,
558                     NPReason reason, void* notifyData )
559 {
560     /***** Insert NPP_URLNotify code here *****\
561     PluginInstance* p_plugin;
562     if (instance != NULL)
563         p_plugin = (PluginInstance*) instance->pdata;
564     \*********************************************/
565 }
566
567
568 void NPP_Print( NPP instance, NPPrint* printInfo )
569 {
570     if( printInfo == NULL )
571     {
572         return;
573     }
574
575     if( instance != NULL )
576     {
577         /***** Insert NPP_Print code here *****\
578         PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
579         \**************************************/
580
581         if( printInfo->mode == NP_FULL )
582         {
583             /*
584              * PLUGIN DEVELOPERS:
585              *  If your plugin would like to take over
586              *  printing completely when it is in full-screen mode,
587              *  set printInfo->pluginPrinted to TRUE and print your
588              *  plugin as you see fit.  If your plugin wants Netscape
589              *  to handle printing in this case, set
590              *  printInfo->pluginPrinted to FALSE (the default) and
591              *  do nothing.  If you do want to handle printing
592              *  yourself, printOne is true if the print button
593              *  (as opposed to the print menu) was clicked.
594              *  On the Macintosh, platformPrint is a THPrint; on
595              *  Windows, platformPrint is a structure
596              *  (defined in npapi.h) containing the printer name, port,
597              *  etc.
598              */
599
600             /***** Insert NPP_Print code here *****\
601             void* platformPrint =
602                 printInfo->print.fullPrint.platformPrint;
603             NPBool printOne =
604                 printInfo->print.fullPrint.printOne;
605             \**************************************/
606
607             /* Do the default*/
608             printInfo->print.fullPrint.pluginPrinted = FALSE;
609         }
610         else
611         {
612             /* If not fullscreen, we must be embedded */
613             /*
614              * PLUGIN DEVELOPERS:
615              *  If your plugin is embedded, or is full-screen
616              *  but you returned false in pluginPrinted above, NPP_Print
617              *  will be called with mode == NP_EMBED.  The NPWindow
618              *  in the printInfo gives the location and dimensions of
619              *  the embedded plugin on the printed page.  On the
620              *  Macintosh, platformPrint is the printer port; on
621              *  Windows, platformPrint is the handle to the printing
622              *  device context.
623              */
624
625             /***** Insert NPP_Print code here *****\
626             NPWindow* printWindow =
627                 &(printInfo->print.embedPrint.window);
628             void* platformPrint =
629                 printInfo->print.embedPrint.platformPrint;
630             \**************************************/
631         }
632     }
633 }
634
635 /******************************************************************************
636  * Windows-only methods
637  *****************************************************************************/
638 #ifdef XP_WIN
639 LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar )
640 {
641     VlcPlugin* p_plugin = (VlcPlugin*) GetProp( p_hwnd, "w00t" );
642
643     switch( i_msg )
644     {
645 #if !USE_LIBVLC
646         case WM_PAINT:
647         {
648             PAINTSTRUCT paintstruct;
649             HDC hdc;
650             RECT rect;
651
652             hdc = BeginPaint( p_hwnd, &paintstruct );
653
654             GetClientRect( p_hwnd, &rect );
655             FillRect( hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH) );
656             TextOut( hdc, p_plugin->i_width / 2 - 40, p_plugin->i_height / 2,
657                      WINDOW_TEXT, strlen(WINDOW_TEXT) );
658
659             EndPaint( p_hwnd, &paintstruct );
660             break;
661         }
662 #endif
663         default:
664             p_plugin->pf_wndproc( p_hwnd, i_msg, wpar, lpar );
665             break;
666     }
667     return 0;
668 }
669 #endif
670
671 /******************************************************************************
672  * UNIX-only methods
673  *****************************************************************************/
674 #ifdef XP_UNIX
675 static void Redraw( Widget w, XtPointer closure, XEvent *event )
676 {
677     VlcPlugin* p_plugin = (VlcPlugin*)closure;
678     GC gc;
679     XGCValues gcv;
680
681     gcv.foreground = BlackPixel( p_plugin->p_display, 0 );
682     gc = XCreateGC( p_plugin->p_display, p_plugin->window, GCForeground, &gcv );
683
684     XFillRectangle( p_plugin->p_display, p_plugin->window, gc,
685                     0, 0, p_plugin->i_width, p_plugin->i_height );
686
687     gcv.foreground = WhitePixel( p_plugin->p_display, 0 );
688     XChangeGC( p_plugin->p_display, gc, GCForeground, &gcv );
689
690     XDrawString( p_plugin->p_display, p_plugin->window, gc,
691                  p_plugin->i_width / 2 - 40, p_plugin->i_height / 2,
692                  WINDOW_TEXT, strlen(WINDOW_TEXT) );
693
694     XFreeGC( p_plugin->p_display, gc );
695 }
696 #endif
697