94df4df8d7cdc7cfd84269a11dca8a52893b447b
[vlc.git] / mozilla / vlcshell.cpp
1 /*****************************************************************************
2  * vlcshell.cpp: a VLC plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 /* Mozilla stuff */
34 #ifdef HAVE_MOZILLA_CONFIG_H
35 #   include <mozilla-config.h>
36 #endif
37
38 /* This is from mozilla java, do we really need it? */
39 #if 0
40 #include <jri.h>
41 #endif
42
43 #include "vlcplugin.h"
44
45 /* Enable/disable debugging printf's for X11 resizing */
46 #undef X11_RESIZE_DEBUG
47
48 #define WINDOW_TEXT "(no video)"
49
50 /*****************************************************************************
51  * Unix-only declarations
52 ******************************************************************************/
53 #ifdef XP_UNIX
54
55 static void Redraw( Widget w, XtPointer closure, XEvent *event );
56 static void Resize( Widget w, XtPointer closure, XEvent *event );
57
58 #endif
59
60 /*****************************************************************************
61  * MacOS-only declarations
62 ******************************************************************************/
63 #ifdef XP_MACOSX
64 #endif
65
66 /*****************************************************************************
67  * Windows-only declarations
68  *****************************************************************************/
69 #ifdef XP_WIN
70
71 static LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar );
72
73 #endif
74
75 /******************************************************************************
76  * UNIX-only API calls
77  *****************************************************************************/
78 char * NPP_GetMIMEDescription( void )
79 {
80     return PLUGIN_MIMETYPES;
81 }
82
83 NPError NPP_GetValue( NPP instance, NPPVariable variable, void *value )
84 {
85
86     static char psz_desc[1000];
87
88     /* plugin class variables */
89     switch( variable )
90     {
91         case NPPVpluginNameString:
92             *((char **)value) = PLUGIN_NAME;
93             return NPERR_NO_ERROR;
94
95         case NPPVpluginDescriptionString:
96             snprintf( psz_desc, sizeof(psz_desc), PLUGIN_DESCRIPTION, VLC_Version() );
97             *((char **)value) = psz_desc;
98             return NPERR_NO_ERROR;
99
100         default:
101             /* move on to instance variables ... */
102             ;
103     }
104
105     if( instance == NULL )
106     {
107         return NPERR_INVALID_INSTANCE_ERROR;
108     }
109
110     /* plugin instance variables */
111
112     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
113     if( NULL == p_plugin )
114     {
115         // plugin has not been initialized yet !
116         return NPERR_INVALID_INSTANCE_ERROR;
117     }
118
119     switch( variable )
120     {
121         case NPPVpluginScriptableNPObject:
122         {
123             /* retrieve plugin root class */
124             NPClass *scriptClass = p_plugin->getScriptClass();
125             if( scriptClass )
126             {
127                 /* create an instance and return it */
128                 *(NPObject**)value = NPN_CreateObject(instance, scriptClass);
129                 return NPERR_NO_ERROR;
130             }
131             break;
132         }
133
134         default:
135             ;
136     }
137     return NPERR_GENERIC_ERROR;
138 }
139
140 /*
141  * there is some confusion in gecko headers regarding definition of this API
142  * NPPVariable is wrongly defined as NPNVariable, which sounds incorrect.
143  */
144
145 NPError NPP_SetValue( NPP instance, NPNVariable variable, void *value )
146 {
147     return NPERR_GENERIC_ERROR;
148 }
149
150 /******************************************************************************
151  * Mac-only API calls
152  *****************************************************************************/
153 #ifdef XP_MACOSX
154 int16 NPP_HandleEvent( NPP instance, void * event )
155 {
156     static UInt32 lastMouseUp = 0;
157
158     if( instance == NULL )
159     {
160         return false;
161     }
162
163     VlcPlugin *p_plugin = (VlcPlugin*)instance->pdata;
164
165     if( p_plugin == NULL )
166     {
167         return false;
168     }
169
170     EventRecord *myEvent = (EventRecord*)event;
171
172     switch( myEvent->what )
173     {
174         case nullEvent:
175             return true;
176         case mouseDown:
177         {
178             if( (myEvent->when - lastMouseUp) < GetDblTime() )
179             {
180                 /* double click */
181                 libvlc_instance_t *p_vlc = p_plugin->getVLC();
182
183                 if( p_vlc )
184                 {
185                     if( libvlc_playlist_isplaying(p_vlc, NULL) )
186                     {
187                         libvlc_media_instance_t *p_md = libvlc_playlist_get_media_instance(p_vlc, NULL);
188                         if( p_md )
189                         {
190                             libvlc_toggle_fullscreen(p_md, NULL);
191                             libvlc_media_instance_release(p_md);
192                         }
193                     }
194                 }
195             }
196             return true;
197         }
198         case mouseUp:
199             lastMouseUp = myEvent->when;
200             return true;
201         case keyUp:
202         case keyDown:
203         case autoKey:
204             return true;
205         case updateEvt:
206         {
207             const NPWindow& npwindow = p_plugin->getWindow();
208             if( npwindow.window )
209             {
210                 int hasVout = FALSE;
211                 libvlc_instance_t *p_vlc = p_plugin->getVLC();
212
213                 if( p_vlc )
214                 {
215                     if( libvlc_playlist_isplaying(p_vlc, NULL) )
216                     {
217                         libvlc_media_instance_t *p_md = libvlc_playlist_get_media_instance(p_vlc, NULL);
218                         if( p_md )
219                         {
220                             hasVout = libvlc_media_instance_has_vout(p_md, NULL);
221                             if( hasVout )
222                             {
223                                 libvlc_rectangle_t area;
224                                 area.left = 0;
225                                 area.top = 0;
226                                 area.right = npwindow.width;
227                                 area.bottom = npwindow.height;
228                                 libvlc_video_redraw_rectangle(p_md, &area, NULL);
229                             }
230                             libvlc_media_instance_release(p_md);
231                         }
232                     }
233                 }
234
235                 if( ! hasVout )
236                 {
237                     /* draw the beautiful "No Picture" */
238
239                     ForeColor(blackColor);
240                     PenMode( patCopy );
241
242                     /* seems that firefox forgets to set the following on occasion (reload) */
243                     SetOrigin(((NP_Port *)npwindow.window)->portx, ((NP_Port *)npwindow.window)->porty);
244
245                     Rect rect;
246                     rect.left = 0;
247                     rect.top = 0;
248                     rect.right = npwindow.width;
249                     rect.bottom = npwindow.height;
250                     PaintRect( &rect );
251
252                     ForeColor(whiteColor);
253                     MoveTo( (npwindow.width-80)/ 2  , npwindow.height / 2 );
254                     DrawText( WINDOW_TEXT , 0 , strlen(WINDOW_TEXT) );
255                 }
256             }
257             return true;
258         }
259         case activateEvt:
260             return false;
261         case NPEventType_GetFocusEvent:
262         case NPEventType_LoseFocusEvent:
263             return true;
264         case NPEventType_AdjustCursorEvent:
265             return false;
266         case NPEventType_MenuCommandEvent:
267             return false;
268         case NPEventType_ClippingChangedEvent:
269             return false;
270         case NPEventType_ScrollingBeginsEvent:
271             return true;
272         case NPEventType_ScrollingEndsEvent:
273             return true;
274         default:
275             ;
276     }
277     return false;
278 }
279 #endif /* XP_MACOSX */
280
281 /******************************************************************************
282  * General Plug-in Calls
283  *****************************************************************************/
284 NPError NPP_Initialize( void )
285 {
286     return NPERR_NO_ERROR;
287 }
288
289 jref NPP_GetJavaClass( void )
290 {
291     return NULL;
292 }
293
294 void NPP_Shutdown( void )
295 {
296     ;
297 }
298
299 NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
300                  char* argn[], char* argv[], NPSavedData* saved )
301 {
302     NPError status;
303
304     if( instance == NULL )
305     {
306         return NPERR_INVALID_INSTANCE_ERROR;
307     }
308
309     VlcPlugin * p_plugin = new VlcPlugin( instance, mode );
310     if( NULL == p_plugin )
311     {
312         return NPERR_OUT_OF_MEMORY_ERROR;
313     }
314
315     status = p_plugin->init(argc, argn, argv);
316     if( NPERR_NO_ERROR == status )
317     {
318         instance->pdata = reinterpret_cast<void*>(p_plugin);
319 #if 0
320         NPN_SetValue(instance, NPPVpluginWindowBool, (void *)false);
321         NPN_SetValue(instance, NPPVpluginTransparentBool, (void *)false);
322 #endif
323     }
324     else
325     {
326         delete p_plugin;
327     }
328     return status;
329 }
330
331 NPError NPP_Destroy( NPP instance, NPSavedData** save )
332 {
333     if( NULL == instance )
334         return NPERR_INVALID_INSTANCE_ERROR;
335
336     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
337     if( NULL == p_plugin )
338         return NPERR_NO_ERROR;
339
340     instance->pdata = NULL;
341
342 #if XP_WIN
343     HWND win = (HWND)p_plugin->getWindow().window;
344     WNDPROC winproc = p_plugin->getWindowProc();
345     if( winproc )
346     {
347         /* reset WNDPROC */
348         SetWindowLong( win, GWL_WNDPROC, (LONG)winproc );
349     }
350 #endif
351
352     delete p_plugin;
353
354     return NPERR_NO_ERROR;
355 }
356
357 NPError NPP_SetWindow( NPP instance, NPWindow* window )
358 {
359     if( ! instance )
360     {
361         return NPERR_INVALID_INSTANCE_ERROR;
362     }
363
364     /* NPP_SetWindow may be called before NPP_New (Opera) */
365     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
366     if( ! p_plugin )
367     {
368         /* we should probably show a splash screen here */
369         return NPERR_NO_ERROR;
370     }
371
372     libvlc_instance_t *p_vlc = p_plugin->getVLC();
373
374     /*
375      * PLUGIN DEVELOPERS:
376      *  Before setting window to point to the
377      *  new window, you may wish to compare the new window
378      *  info to the previous window (if any) to note window
379      *  size changes, etc.
380      */
381
382     /* retrieve current window */
383     NPWindow& curwin = p_plugin->getWindow();
384
385 #ifdef XP_MACOSX
386     if( window && window->window )
387     {
388         /* check if plugin has a new parent window */
389         CGrafPtr drawable = (((NP_Port*) (window->window))->port);
390         if( !curwin.window || drawable != (((NP_Port*) (curwin.window))->port) )
391         {
392             /* set/change parent window */
393             libvlc_video_set_parent(p_vlc, (libvlc_drawable_t)drawable, NULL);
394         }
395
396         /* as MacOS X video output is windowless, set viewport */
397         libvlc_rectangle_t view, clip;
398
399         /*
400         ** browser sets port origin to top-left location of plugin relative to GrafPort
401         ** window origin is set relative to document, which of little use for drawing
402         */
403         view.top     = ((NP_Port*) (window->window))->porty;
404         view.left    = ((NP_Port*) (window->window))->portx;
405         view.bottom  = window->height+view.top;
406         view.right   = window->width+view.left;
407         /* clipRect coordinates are also relative to GrafPort */
408         clip.top     = window->clipRect.top;
409         clip.left    = window->clipRect.left;
410         clip.bottom  = window->clipRect.bottom;
411         clip.right   = window->clipRect.right;
412
413         libvlc_video_set_viewport(p_vlc, &view, &clip, NULL);
414
415         /* remember new window */
416         p_plugin->setWindow(*window);
417     }
418     else if( curwin.window ) {
419         /* change/set parent */
420         libvlc_video_set_parent(p_vlc, 0, NULL);
421         curwin.window = NULL;
422     }
423 #endif /* XP_MACOSX */
424
425 #ifdef XP_WIN
426     if( window && window->window )
427     {
428         /* check if plugin has a new parent window */
429         HWND drawable = (HWND) (window->window);
430         if( !curwin.window || drawable != curwin.window )
431         {
432             /* reset previous window settings */
433             HWND oldwin = (HWND)p_plugin->getWindow().window;
434             WNDPROC oldproc = p_plugin->getWindowProc();
435             if( oldproc )
436             {
437                 /* reset WNDPROC */
438                 SetWindowLong( oldwin, GWL_WNDPROC, (LONG)oldproc );
439             }
440             /* attach our plugin object */
441             SetWindowLongPtr((HWND)drawable, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(p_plugin));
442
443             /* install our WNDPROC */
444             p_plugin->setWindowProc( (WNDPROC)SetWindowLong( drawable,
445                                                            GWL_WNDPROC, (LONG)Manage ) );
446
447             /* change window style to our liking */
448             LONG style = GetWindowLong((HWND)drawable, GWL_STYLE);
449             style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
450             SetWindowLong((HWND)drawable, GWL_STYLE, style);
451
452             /* change/set parent */
453             libvlc_video_set_parent(p_vlc, (libvlc_drawable_t)drawable, NULL);
454
455             /* remember new window */
456             p_plugin->setWindow(*window);
457
458             /* Redraw window */
459             InvalidateRect( (HWND)drawable, NULL, TRUE );
460             UpdateWindow( (HWND)drawable );
461         }
462     }
463     else if ( curwin.window )
464     {
465         /* reset WNDPROC */
466         HWND oldwin = (HWND)curwin.window;
467         SetWindowLong( oldwin, GWL_WNDPROC, (LONG)(p_plugin->getWindowProc()) );
468         p_plugin->setWindowProc(NULL);
469         /* change/set parent */
470         libvlc_video_set_parent(p_vlc, 0, NULL);
471         curwin.window = NULL;
472     }
473 #endif /* XP_WIN */
474
475 #ifdef XP_UNIX
476     if( window && window->window )
477     {
478         Window  drawable   = (Window) window->window;
479         if( !curwin.window || drawable != (Window)curwin.window )
480         {
481             Display *p_display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
482
483             XResizeWindow( p_display, drawable, window->width, window->height );
484             Widget w = XtWindowToWidget( p_display, drawable );
485
486             XtAddEventHandler( w, ExposureMask, FALSE, (XtEventHandler)Redraw, p_plugin );
487             XtAddEventHandler( w, StructureNotifyMask, FALSE, (XtEventHandler)Resize, p_plugin );
488
489             /* set/change parent window */
490             libvlc_video_set_parent(p_vlc, (libvlc_drawable_t)drawable, NULL);
491
492             /* remember window */
493             p_plugin->setWindow(*window);
494
495             Redraw( w, (XtPointer)p_plugin, NULL );
496         }
497     }
498     else if ( curwin.window )
499     {
500         /* change/set parent */
501         libvlc_video_set_parent(p_vlc, 0, NULL);
502         curwin.window = NULL;
503     }
504 #endif /* XP_UNIX */
505
506     if( !p_plugin->b_stream )
507     {
508         if( p_plugin->psz_target )
509         {
510             if( libvlc_playlist_add( p_vlc, p_plugin->psz_target, NULL, NULL ) != -1 )
511             {
512                 if( p_plugin->b_autoplay )
513                 {
514                     libvlc_playlist_play(p_vlc, 0, 0, NULL, NULL);
515                 }
516             }
517             p_plugin->b_stream = VLC_TRUE;
518         }
519     }
520     return NPERR_NO_ERROR;
521 }
522
523 NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream,
524                        NPBool seekable, uint16 *stype )
525 {
526     if( NULL == instance  )
527     {
528         return NPERR_INVALID_INSTANCE_ERROR;
529     }
530
531     VlcPlugin *p_plugin = reinterpret_cast<VlcPlugin *>(instance->pdata);
532     if( NULL == p_plugin )
533     {
534         return NPERR_INVALID_INSTANCE_ERROR;
535     }
536
537    /*
538    ** Firefox/Mozilla may decide to open a stream from the URL specified
539    ** in the SRC parameter of the EMBED tag and pass it to us
540    **
541    ** since VLC will open the SRC URL as well, we're not interested in
542    ** that stream. Otherwise, we'll take it and queue it up in the playlist
543    */
544     if( !p_plugin->psz_target || strcmp(stream->url, p_plugin->psz_target) )
545     {
546         /* TODO: use pipes !!!! */
547         *stype = NP_ASFILEONLY;
548         return NPERR_NO_ERROR;
549     }
550     return NPERR_GENERIC_ERROR;
551 }
552
553 int32 NPP_WriteReady( NPP instance, NPStream *stream )
554 {
555     /* TODO */
556     return 8*1024;
557 }
558
559
560 int32 NPP_Write( NPP instance, NPStream *stream, int32 offset,
561                  int32 len, void *buffer )
562 {
563     /* TODO */
564     return len;
565 }
566
567
568 NPError NPP_DestroyStream( NPP instance, NPStream *stream, NPError reason )
569 {
570     if( instance == NULL )
571     {
572         return NPERR_INVALID_INSTANCE_ERROR;
573     }
574     return NPERR_NO_ERROR;
575 }
576
577
578 void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* fname )
579 {
580     if( instance == NULL )
581     {
582         return;
583     }
584
585     VlcPlugin *p_plugin = reinterpret_cast<VlcPlugin *>(instance->pdata);
586     if( NULL == p_plugin )
587     {
588         return;
589     }
590
591     if( libvlc_playlist_add( p_plugin->getVLC(), fname, stream->url, NULL ) != -1 )
592     {
593         if( p_plugin->b_autoplay )
594         {
595             libvlc_playlist_play( p_plugin->getVLC(), 0, 0, NULL, NULL);
596         }
597     }
598 }
599
600
601 void NPP_URLNotify( NPP instance, const char* url,
602                     NPReason reason, void* notifyData )
603 {
604     /***** Insert NPP_URLNotify code here *****\
605     PluginInstance* p_plugin;
606     if (instance != NULL)
607         p_plugin = (PluginInstance*) instance->pdata;
608     \*********************************************/
609 }
610
611
612 void NPP_Print( NPP instance, NPPrint* printInfo )
613 {
614     if( printInfo == NULL )
615     {
616         return;
617     }
618
619     if( instance != NULL )
620     {
621         /***** Insert NPP_Print code here *****\
622         PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
623         \**************************************/
624
625         if( printInfo->mode == NP_FULL )
626         {
627             /*
628              * PLUGIN DEVELOPERS:
629              *  If your plugin would like to take over
630              *  printing completely when it is in full-screen mode,
631              *  set printInfo->pluginPrinted to TRUE and print your
632              *  plugin as you see fit.  If your plugin wants Netscape
633              *  to handle printing in this case, set
634              *  printInfo->pluginPrinted to FALSE (the default) and
635              *  do nothing.  If you do want to handle printing
636              *  yourself, printOne is true if the print button
637              *  (as opposed to the print menu) was clicked.
638              *  On the Macintosh, platformPrint is a THPrint; on
639              *  Windows, platformPrint is a structure
640              *  (defined in npapi.h) containing the printer name, port,
641              *  etc.
642              */
643
644             /***** Insert NPP_Print code here *****\
645             void* platformPrint =
646                 printInfo->print.fullPrint.platformPrint;
647             NPBool printOne =
648                 printInfo->print.fullPrint.printOne;
649             \**************************************/
650
651             /* Do the default*/
652             printInfo->print.fullPrint.pluginPrinted = FALSE;
653         }
654         else
655         {
656             /* If not fullscreen, we must be embedded */
657             /*
658              * PLUGIN DEVELOPERS:
659              *  If your plugin is embedded, or is full-screen
660              *  but you returned false in pluginPrinted above, NPP_Print
661              *  will be called with mode == NP_EMBED.  The NPWindow
662              *  in the printInfo gives the location and dimensions of
663              *  the embedded plugin on the printed page.  On the
664              *  Macintosh, platformPrint is the printer port; on
665              *  Windows, platformPrint is the handle to the printing
666              *  device context.
667              */
668
669             /***** Insert NPP_Print code here *****\
670             NPWindow* printWindow =
671                 &(printInfo->print.embedPrint.window);
672             void* platformPrint =
673                 printInfo->print.embedPrint.platformPrint;
674             \**************************************/
675         }
676     }
677 }
678
679 /******************************************************************************
680  * Windows-only methods
681  *****************************************************************************/
682 #if XP_WIN
683 static LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar )
684 {
685     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(GetWindowLongPtr(p_hwnd, GWLP_USERDATA));
686
687     switch( i_msg )
688     {
689         case WM_ERASEBKGND:
690             return 1L;
691
692         case WM_PAINT:
693         {
694             PAINTSTRUCT paintstruct;
695             HDC hdc;
696             RECT rect;
697
698             hdc = BeginPaint( p_hwnd, &paintstruct );
699
700             GetClientRect( p_hwnd, &rect );
701
702             FillRect( hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) );
703             SetTextColor(hdc, RGB(255, 255, 255));
704             SetBkColor(hdc, RGB(0, 0, 0));
705             DrawText( hdc, WINDOW_TEXT, strlen(WINDOW_TEXT), &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
706
707             EndPaint( p_hwnd, &paintstruct );
708             return 0L;
709         }
710         default:
711             /* delegate to default handler */
712             return CallWindowProc(p_plugin->getWindowProc(), p_hwnd, i_msg, wpar, lpar );
713     }
714 }
715 #endif /* XP_WIN */
716
717 /******************************************************************************
718  * UNIX-only methods
719  *****************************************************************************/
720 #ifdef XP_UNIX
721 static void Redraw( Widget w, XtPointer closure, XEvent *event )
722 {
723     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(closure);
724     const NPWindow& window = p_plugin->getWindow();
725     GC gc;
726     XGCValues gcv;
727
728     Window  drawable   = (Window) window.window;
729     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
730
731     gcv.foreground = BlackPixel( p_display, 0 );
732     gc = XCreateGC( p_display, drawable, GCForeground, &gcv );
733
734     XFillRectangle( p_display, drawable, gc,
735                     0, 0, window.width, window.height );
736
737     gcv.foreground = WhitePixel( p_display, 0 );
738     XChangeGC( p_display, gc, GCForeground, &gcv );
739
740     XDrawString( p_display, drawable, gc,
741                  window.width / 2 - 40, window.height / 2,
742                  WINDOW_TEXT, strlen(WINDOW_TEXT) );
743
744     XFreeGC( p_display, gc );
745 }
746
747 static void Resize ( Widget w, XtPointer closure, XEvent *event )
748 {
749     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(closure);
750     const NPWindow& window = p_plugin->getWindow();
751     Window  drawable   = (Window) window.window;
752     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
753
754     int i_ret;
755     Window root_return, parent_return, * children_return;
756     Window base_window;
757     unsigned int i_nchildren;
758
759 #ifdef X11_RESIZE_DEBUG
760     XWindowAttributes attr;
761
762     if( event && event->type == ConfigureNotify )
763     {
764         fprintf( stderr, "vlcshell::Resize() ConfigureNotify %d x %d, "
765                  "send_event ? %s\n", event->xconfigure.width,
766                  event->xconfigure.height,
767                  event->xconfigure.send_event ? "TRUE" : "FALSE" );
768     }
769 #endif /* X11_RESIZE_DEBUG */
770
771     if( ! p_plugin->setSize(window.width, window.height) )
772     {
773         /* size already set */
774         return;
775     }
776
777
778     i_ret = XResizeWindow( p_display, drawable, window.width, window.height );
779
780 #ifdef X11_RESIZE_DEBUG
781     fprintf( stderr,
782              "vlcshell::Resize() XResizeWindow(owner) returned %d\n", i_ret );
783
784     XGetWindowAttributes ( p_display, drawable, &attr );
785
786     /* X is asynchronous, so the current size reported here is not
787        necessarily the requested size as the Resize request may not
788        yet have been handled by the plugin host */
789     fprintf( stderr, "vlcshell::Resize() current (owner) size %d x %d\n",
790              attr.width, attr.height );
791 #endif /* X11_RESIZE_DEBUG */
792
793     XQueryTree( p_display, drawable,
794                 &root_return, &parent_return, &children_return,
795                 &i_nchildren );
796
797     if( i_nchildren > 0 )
798     {
799         /* XXX: Make assumptions related to the window parenting structure in
800            vlc/modules/video_output/x11/xcommon.c */
801         base_window = children_return[i_nchildren - 1];
802
803 #ifdef X11_RESIZE_DEBUG
804         fprintf( stderr, "vlcshell::Resize() got %d children\n", i_nchildren );
805         fprintf( stderr, "vlcshell::Resize() got base_window %p\n",
806                  base_window );
807 #endif /* X11_RESIZE_DEBUG */
808
809         i_ret = XResizeWindow( p_display, base_window,
810                 window.width, window.height );
811
812 #ifdef X11_RESIZE_DEBUG
813         fprintf( stderr,
814                  "vlcshell::Resize() XResizeWindow(base) returned %d\n",
815                  i_ret );
816
817         XGetWindowAttributes( p_display, base_window, &attr );
818
819         fprintf( stderr, "vlcshell::Resize() new size %d x %d\n",
820                  attr.width, attr.height );
821 #endif /* X11_RESIZE_DEBUG */
822     }
823 }
824
825 #endif /* XP_UNIX */
826