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