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