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