]> git.sesse.net Git - vlc/blob - modules/video_output/wingdi.c
Leverage libgcrypt CounTeR mode implementation to simplify our code
[vlc] / modules / video_output / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc_interface.h>
33 #include <vlc_playlist.h>
34 #include <vlc_vout.h>
35
36 #include <commctrl.h>
37
38 #define SHFS_SHOWSIPBUTTON 0x0004
39 #define SHFS_HIDESIPBUTTON 0x0008
40
41 #if defined(UNDER_CE) && !defined(__PLUGIN__) /*FIXME*/
42 #   define MENU_HEIGHT 26
43     BOOL SHFullScreen(HWND hwndRequester, DWORD dwState);
44 #else
45 #   define MENU_HEIGHT 0
46 #   define SHFullScreen(a,b)
47 #endif
48
49 #ifdef MODULE_NAME_IS_wingapi
50     typedef struct GXDisplayProperties {
51         DWORD cxWidth;
52         DWORD cyHeight;
53         long cbxPitch;
54         long cbyPitch;
55         long cBPP;
56         DWORD ffFormat;
57     } GXDisplayProperties;
58
59     typedef struct GXScreenRect {
60         DWORD dwTop;
61         DWORD dwLeft;
62         DWORD dwWidth;
63         DWORD dwHeight;
64     } GXScreenRect;
65
66 #   define GX_FULLSCREEN    0x01
67 #   define GX_NORMALKEYS    0x02
68 #   define GX_LANDSCAPEKEYS 0x03
69
70 #   ifndef kfLandscape
71 #       define kfLandscape      0x8
72 #       define kfPalette        0x10
73 #       define kfDirect         0x20
74 #       define kfDirect555      0x40
75 #       define kfDirect565      0x80
76 #       define kfDirect888      0x100
77 #       define kfDirect444      0x200
78 #       define kfDirectInverted 0x400
79 #   endif
80 #endif /* MODULE_NAME_IS_wingapi */
81
82 #define MAX_DIRECTBUFFERS 10
83
84 #ifdef UNDER_CE
85 #ifndef WS_OVERLAPPEDWINDOW
86 #   define WS_OVERLAPPEDWINDOW 0xcf0000
87 #endif
88 #ifndef WS_EX_NOPARENTNOTIFY
89 #   define WS_EX_NOPARENTNOTIFY 4
90 #endif
91 #ifndef WS_EX_APPWINDOW
92 #define WS_EX_APPWINDOW 0x40000
93 #endif
94 #define SetWindowLongPtr SetWindowLong
95 #define GetWindowLongPtr GetWindowLong
96 #define GWLP_USERDATA GWL_USERDATA
97 #define AdjustWindowRect(a,b,c)
98 #endif //UNDER_CE
99
100 #ifndef WS_NONAVDONEBUTTON
101 #define WS_NONAVDONEBUTTON 0
102 #endif
103 /*****************************************************************************
104  * Local prototypes
105  *****************************************************************************/
106 static int  OpenVideo  ( vlc_object_t * );
107 static void CloseVideo ( vlc_object_t * );
108
109 static int  Init      ( vout_thread_t * );
110 static void End       ( vout_thread_t * );
111 static int  Manage    ( vout_thread_t * );
112 static void Render    ( vout_thread_t *, picture_t * );
113 #ifdef MODULE_NAME_IS_wingapi
114 static void DisplayGAPI( vout_thread_t *, picture_t * );
115 static int GAPILockSurface( vout_thread_t *, picture_t * );
116 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
117 #else
118 static void DisplayGDI( vout_thread_t *, picture_t * );
119 #endif
120 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
121
122 static void EventThread        ( vlc_object_t * );
123 static long FAR PASCAL WndProc ( HWND, UINT, WPARAM, LPARAM );
124 static void InitBuffers        ( vout_thread_t * );
125 static void UpdateRects        ( vout_thread_t *, vlc_bool_t );
126
127 static int Control( vout_thread_t *p_vout, int i_query, va_list args );
128
129 /*****************************************************************************
130  * Private structure
131  *****************************************************************************/
132 struct vout_sys_t
133 {
134     /* The event thread */
135     vlc_object_t * p_event;
136
137     /* Our video output window */
138     HWND hwnd;
139     HWND hvideownd;
140     HWND hfswnd;
141     int  i_depth;
142     HWND                 hparent;             /* Handle of the parent window */
143     WNDPROC              pf_wndproc;             /* Window handling callback */
144     volatile uint16_t    i_changes;     /* changes made to the video display */
145     RECT window_placement;
146
147     /* Window position and size */
148     int          i_window_x;
149     int          i_window_y;
150     int          i_window_width;
151     int          i_window_height;
152     int          i_window_style;
153     int          render_width;
154     int          render_height;
155
156     /* Coordinates of src and dest images (used when blitting to display) */
157     RECT         rect_src;
158     RECT         rect_src_clipped;
159     RECT         rect_dest;
160     RECT         rect_dest_clipped;
161     RECT         rect_parent;
162     RECT         rect_display;
163
164     /* Our offscreen bitmap and its framebuffer */
165     HDC        off_dc;
166     HBITMAP    off_bitmap;
167     uint8_t *  p_pic_buffer;
168     int        i_pic_pitch;
169     int        i_pic_pixel_pitch;
170
171     BITMAPINFO bitmapinfo;
172     RGBQUAD    red;
173     RGBQUAD    green;
174     RGBQUAD    blue;
175
176     /* WINCE stuff */
177     vlc_bool_t   b_video_display;
178
179     /* Window focus states */
180     vlc_bool_t b_focus;
181     vlc_bool_t b_parent_focus;
182
183 #ifdef MODULE_NAME_IS_wingapi
184     HINSTANCE  gapi_dll;                    /* handle of the opened gapi dll */
185
186     /* GAPI functions */
187     int (*GXOpenDisplay)( HWND hWnd, DWORD dwFlags );
188     int (*GXCloseDisplay)();
189     void *(*GXBeginDraw)();
190     int (*GXEndDraw)();
191     GXDisplayProperties (*GXGetDisplayProperties)();
192     int (*GXSuspend)();
193     int (*GXResume)();
194 #endif
195 };
196
197 #define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
198 #define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
199 #define GXBeginDraw p_vout->p_sys->GXBeginDraw
200 #define GXEndDraw p_vout->p_sys->GXEndDraw
201 #define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
202
203 #ifdef MODULE_NAME_IS_wingapi
204 #   define GXSuspend p_vout->p_sys->GXSuspend
205 #   define GXResume p_vout->p_sys->GXResume
206 #else
207 #   define GXSuspend()
208 #   define GXResume()
209 #endif
210
211 #define DX_POSITION_CHANGE 0x1000
212
213 /*****************************************************************************
214  * Module descriptor
215  *****************************************************************************/
216 vlc_module_begin();
217     set_category( CAT_VIDEO );
218     set_subcategory( SUBCAT_VIDEO_VOUT );
219 #ifdef MODULE_NAME_IS_wingapi
220     set_shortname( "Windows GAPI" );
221     set_description( _("Windows GAPI video output") );
222     set_capability( "video output", 20 );
223 #else
224     set_shortname( "Windows GDI" );
225     set_description( _("Windows GDI video output") );
226     set_capability( "video output", 10 );
227 #endif
228     set_callbacks( OpenVideo, CloseVideo );
229 vlc_module_end();
230
231 /*****************************************************************************
232  * OpenVideo: activate GDI video thread output method
233  *****************************************************************************/
234 static int OpenVideo ( vlc_object_t *p_this )
235 {
236     vout_thread_t * p_vout = (vout_thread_t *)p_this;
237     vlc_value_t val;
238
239     p_vout->p_sys = (vout_sys_t *)malloc( sizeof(vout_sys_t) );
240     if( !p_vout->p_sys ) return VLC_ENOMEM;
241
242 #ifdef MODULE_NAME_IS_wingapi
243     /* Load GAPI */
244     p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
245     if( p_vout->p_sys->gapi_dll == NULL )
246     {
247         msg_Warn( p_vout, "failed loading gx.dll" );
248         free( p_vout->p_sys );
249         return VLC_EGENERIC;
250     }
251
252     GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
253         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
254     GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
255         _T("?GXCloseDisplay@@YAHXZ") );
256     GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
257         _T("?GXBeginDraw@@YAPAXXZ") );
258     GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
259         _T("?GXEndDraw@@YAHXZ") );
260     GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
261         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
262     GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
263         _T("?GXSuspend@@YAHXZ") );
264     GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
265         _T("?GXResume@@YAHXZ") );
266
267     if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
268         !GXGetDisplayProperties || !GXSuspend || !GXResume )
269     {
270         msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
271         free( p_vout->p_sys );
272         return VLC_EGENERIC;
273     }
274
275     msg_Dbg( p_vout, "GAPI DLL loaded" );
276
277     p_vout->p_sys->render_width = p_vout->render.i_width;
278     p_vout->p_sys->render_height = p_vout->render.i_height;
279 #endif
280
281     p_vout->p_sys->p_event = (vlc_object_t *)
282         vlc_object_create( p_vout, VLC_OBJECT_GENERIC );
283     if( !p_vout->p_sys->p_event )
284     {
285         free( p_vout->p_sys );
286         return VLC_ENOMEM;
287     }
288
289     var_Create( p_vout->p_sys->p_event, "p_vout", VLC_VAR_ADDRESS );
290     val.p_address = (void *)p_vout;
291     var_Set( p_vout->p_sys->p_event, "p_vout", val );
292
293     SetRectEmpty( &p_vout->p_sys->rect_display );
294     SetRectEmpty( &p_vout->p_sys->rect_parent );
295
296     if( vlc_thread_create( p_vout->p_sys->p_event, "GDI Event Thread",
297                            EventThread, 0, 1 ) )
298     {
299         msg_Err( p_vout, "cannot spawn EventThread" );
300         return VLC_ETHREAD;
301     }
302
303     p_vout->pf_init = Init;
304     p_vout->pf_end = End;
305     p_vout->pf_manage = Manage;
306     p_vout->pf_render = Render;
307 #ifdef MODULE_NAME_IS_wingapi
308     p_vout->pf_display = DisplayGAPI;
309 #else
310     p_vout->pf_display = DisplayGDI;
311 #endif
312     p_vout->p_sys->i_changes = 0;
313
314     p_vout->p_sys->b_focus = 0;
315     p_vout->p_sys->b_parent_focus = 0;
316
317     return VLC_SUCCESS;
318 }
319
320 /*****************************************************************************
321  * CloseVideo: deactivate the GDI video output
322  *****************************************************************************/
323 static void CloseVideo ( vlc_object_t *p_this )
324 {
325     vout_thread_t * p_vout = (vout_thread_t *)p_this;
326
327     p_vout->p_sys->p_event->b_die = VLC_TRUE;
328     PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0 );
329     vlc_thread_join( p_vout->p_sys->p_event );
330
331 #ifdef MODULE_NAME_IS_wingapi
332     FreeLibrary( p_vout->p_sys->gapi_dll );
333 #endif
334
335     var_Destroy( p_vout->p_sys->p_event, "p_vout" );
336     vlc_object_destroy( p_vout->p_sys->p_event );
337     free( p_vout->p_sys );
338 }
339
340 /*****************************************************************************
341  * Init: initialize video thread output method
342  *****************************************************************************/
343 static int Init( vout_thread_t *p_vout )
344 {
345     picture_t *p_pic;
346
347     p_vout->p_sys->rect_display.left = 0;
348     p_vout->p_sys->rect_display.top = 0;
349     p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
350     p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
351
352     p_vout->p_sys->b_video_display = VLC_TRUE;
353     p_vout->p_sys->p_event->b_die = VLC_FALSE;
354
355     I_OUTPUTPICTURES = 0;
356
357     /* Initialize the output structure */
358     switch( p_vout->p_sys->i_depth )
359     {
360     case 8:
361         p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
362         p_vout->output.pf_setpalette = SetPalette;
363         break;
364     case 15:
365         p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
366         p_vout->output.i_rmask  = 0x7c00;
367         p_vout->output.i_gmask  = 0x03e0;
368         p_vout->output.i_bmask  = 0x001f;
369         break;
370     case 16:
371         p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
372         p_vout->output.i_rmask  = 0xf800;
373         p_vout->output.i_gmask  = 0x07e0;
374         p_vout->output.i_bmask  = 0x001f;
375         break;
376     case 24:
377         p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
378         p_vout->output.i_rmask  = 0x00ff0000;
379         p_vout->output.i_gmask  = 0x0000ff00;
380         p_vout->output.i_bmask  = 0x000000ff;
381         break;
382     case 32:
383         p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
384         p_vout->output.i_rmask  = 0x00ff0000;
385         p_vout->output.i_gmask  = 0x0000ff00;
386         p_vout->output.i_bmask  = 0x000000ff;
387         break;
388     default:
389         msg_Err( p_vout, "screen depth %i not supported",
390                  p_vout->p_sys->i_depth );
391         return VLC_EGENERIC;
392         break;
393     }
394
395     p_pic = &p_vout->p_picture[0];
396
397 #ifdef MODULE_NAME_IS_wingapi
398     p_vout->output.i_width  = 0;
399     p_vout->output.i_height = 0;
400     p_pic->pf_lock  = GAPILockSurface;
401     p_pic->pf_unlock = GAPIUnlockSurface;
402     Manage( p_vout );
403     GAPILockSurface( p_vout, p_pic );
404     p_vout->i_changes = 0;
405     p_vout->output.i_width  = p_vout->p_sys->render_width;
406     p_vout->output.i_height = p_vout->p_sys->render_height;
407
408 #else
409     p_vout->output.i_width  = p_vout->render.i_width;
410     p_vout->output.i_height = p_vout->render.i_height;
411
412     p_vout->fmt_out = p_vout->fmt_in;
413     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
414 #endif
415
416     p_vout->output.i_aspect = p_vout->render.i_aspect;
417
418     p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
419     p_pic->p->i_lines = p_vout->output.i_height;
420     p_pic->p->i_visible_lines = p_vout->output.i_height;
421     p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
422     p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
423     p_pic->p->i_visible_pitch = p_vout->output.i_width *
424         p_pic->p->i_pixel_pitch;
425     p_pic->i_planes = 1;
426     p_pic->i_status = DESTROYED_PICTURE;
427     p_pic->i_type   = DIRECT_PICTURE;
428
429     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
430
431     return VLC_SUCCESS;
432 }
433
434 /*****************************************************************************
435  * End: terminate video thread output method
436  *****************************************************************************/
437 static void End( vout_thread_t *p_vout )
438 {
439 }
440
441 /*****************************************************************************
442  * Manage: handle events
443  *****************************************************************************
444  * This function should be called regularly by video output thread. It manages
445  * console events. It returns a non null value on error.
446  *****************************************************************************/
447 static int Manage( vout_thread_t *p_vout )
448 {
449 #ifndef UNDER_CE
450     WINDOWPLACEMENT window_placement;
451 #endif
452
453     /* If we do not control our window, we check for geometry changes
454      * ourselves because the parent might not send us its events. */
455     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
456     {
457         RECT rect_parent;
458         POINT point;
459
460         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
461         point.x = point.y = 0;
462         ClientToScreen( p_vout->p_sys->hparent, &point );
463         OffsetRect( &rect_parent, point.x, point.y );
464
465         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
466         {
467             int i_x, i_y, i_width, i_height;
468             p_vout->p_sys->rect_parent = rect_parent;
469
470             /* This one is to force the update even if only
471              * the position has changed */
472             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
473                           rect_parent.right - rect_parent.left,
474                           rect_parent.bottom - rect_parent.top, 0 );
475
476             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
477                           rect_parent.right - rect_parent.left,
478                           rect_parent.bottom - rect_parent.top, 0 );
479
480             vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
481                                rect_parent.bottom - rect_parent.top,
482                                &i_x, &i_y, &i_width, &i_height );
483
484             SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
485                           i_x, i_y, i_width, i_height, 0 );
486         }
487     }
488
489     /* We used to call the Win32 PeekMessage function here to read the window
490      * messages. But since window can stay blocked into this function for a
491      * long time (for example when you move your window on the screen), I
492      * decided to isolate PeekMessage in another thread. */
493
494     /*
495      * Fullscreen change
496      */
497     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
498         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
499     {
500         int i_style = 0;
501         vlc_value_t val;
502
503         HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
504             p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
505
506         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
507
508         /* We need to switch between Maximized and Normal sized window */
509 #ifndef UNDER_CE
510         window_placement.length = sizeof(WINDOWPLACEMENT);
511         GetWindowPlacement( hwnd, &window_placement );
512 #endif
513         if( p_vout->b_fullscreen )
514         {
515 #ifndef UNDER_CE
516             /* Change window style, no borders and no title bar */
517             int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
518             SetWindowLong( hwnd, GWL_STYLE, i_style );
519
520             if( p_vout->p_sys->hparent )
521             {
522                 /* Retrieve current window position so fullscreen will happen
523                  * on the right screen */
524                 POINT point = {0,0};
525                 RECT rect;
526                 ClientToScreen( p_vout->p_sys->hwnd, &point );
527                 GetClientRect( p_vout->p_sys->hwnd, &rect );
528                 SetWindowPos( hwnd, 0, point.x, point.y,
529                               rect.right, rect.bottom,
530                               SWP_NOZORDER|SWP_FRAMECHANGED );
531                 GetWindowPlacement( hwnd, &window_placement );
532             }
533
534             /* Maximize window */
535             window_placement.showCmd = SW_SHOWMAXIMIZED;
536             SetWindowPlacement( hwnd, &window_placement );
537             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
538                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
539 #endif
540
541             if( p_vout->p_sys->hparent )
542             {
543                 RECT rect;
544                 GetClientRect( hwnd, &rect );
545                 SetParent( p_vout->p_sys->hwnd, hwnd );
546                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
547                               rect.right, rect.bottom,
548                               SWP_NOZORDER|SWP_FRAMECHANGED );
549             }
550
551             ShowWindow( hwnd, SW_SHOW );
552             SetForegroundWindow( hwnd );
553         }
554         else
555         {
556             /* Change window style, no borders and no title bar */
557             //SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
558
559 #ifndef UNDER_CE
560             /* Normal window */
561             window_placement.showCmd = SW_SHOWNORMAL;
562             SetWindowPlacement( hwnd, &window_placement );
563             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
564                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
565 #endif
566
567             if( p_vout->p_sys->hparent )
568             {
569                 RECT rect;
570                 GetClientRect( p_vout->p_sys->hparent, &rect );
571                 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
572                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
573                               rect.right, rect.bottom,
574                               SWP_NOZORDER|SWP_FRAMECHANGED );
575
576                 ShowWindow( hwnd, SW_HIDE );
577                 SetForegroundWindow( p_vout->p_sys->hparent );
578             }
579
580             /* Make sure the mouse cursor is displayed */
581             //PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
582         }
583
584         /* Change window style, borders and title bar */
585         ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
586         UpdateWindow( p_vout->p_sys->hwnd );
587
588         /* Update the object variable and trigger callback */
589         val.b_bool = p_vout->b_fullscreen;
590         var_Set( p_vout, "fullscreen", val );
591
592         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
593         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
594     }
595
596     return VLC_SUCCESS;
597 }
598
599 /*****************************************************************************
600  * Render: render previously calculated output
601  *****************************************************************************/
602 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
603 {
604     /* No need to do anything, the fake direct buffers stay as they are */
605 }
606
607 /*****************************************************************************
608  * Display: displays previously rendered output
609  *****************************************************************************/
610 #define rect_src p_vout->p_sys->rect_src
611 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
612 #define rect_dest p_vout->p_sys->rect_dest
613 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
614
615 #ifndef MODULE_NAME_IS_wingapi
616 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
617 {
618     vout_sys_t *p_sys = p_vout->p_sys;
619     RECT rect_dst = rect_dest_clipped;
620     HDC hdc = GetDC( p_sys->hvideownd );
621
622     OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
623     SelectObject( p_sys->off_dc, p_sys->off_bitmap );
624
625     if( rect_dest_clipped.right - rect_dest_clipped.left !=
626         rect_src_clipped.right - rect_src_clipped.left ||
627         rect_dest_clipped.bottom - rect_dest_clipped.top !=
628         rect_src_clipped.bottom - rect_src_clipped.top )
629     {
630         StretchBlt( hdc, rect_dst.left, rect_dst.top,
631                     rect_dst.right, rect_dst.bottom,
632                     p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
633                     rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
634     }
635     else
636     {
637         BitBlt( hdc, rect_dst.left, rect_dst.top,
638                 rect_dst.right, rect_dst.bottom,
639                 p_sys->off_dc, rect_src_clipped.left,
640                 rect_src_clipped.top, SRCCOPY );
641     }
642
643     ReleaseDC( p_sys->hwnd, hdc );
644 }
645 #else
646
647 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
648 {
649     vout_sys_t *p_sys = p_vout->p_sys;
650     int i_x, i_y, i_width, i_height;
651     RECT video_rect;
652     POINT point;
653
654     /* Undo the display */
655     if( ( GetForegroundWindow() != GetParent(p_sys->hwnd) ) ||
656         ( p_sys->b_video_display == VLC_FALSE ) )
657     {
658         //return VLC_EGENERIC;
659     }
660
661     GetClientRect( p_sys->hwnd, &video_rect);
662     vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
663                        video_rect.bottom - video_rect.top,
664                        &i_x, &i_y, &i_width, &i_height );
665     point.x = point.y = 0;
666     ClientToScreen( p_sys->hwnd, &point );
667     i_x += point.x + video_rect.left;
668     i_y += point.y + video_rect.top;
669
670     if( i_width != p_vout->output.i_width ||
671         i_height != p_vout->output.i_height )
672     {
673         GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
674
675         p_sys->render_width = i_width;
676         p_sys->render_height = i_height;
677         p_vout->i_changes |= VOUT_SIZE_CHANGE;
678
679         msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
680                  i_width, i_height, p_vout->output.i_width,
681                  p_vout->output.i_height );
682
683         p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
684         p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
685         return VLC_EGENERIC;
686     }
687     else
688     {
689         GXDisplayProperties gxdisplayprop;
690         RECT display_rect, dest_rect;
691         uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
692
693         video_rect.left = i_x; video_rect.top = i_y;
694         video_rect.right = i_x + i_width;
695         video_rect.bottom = i_y + i_height;
696
697         gxdisplayprop = GXGetDisplayProperties();
698         display_rect.left = 0; display_rect.top = 0;
699         display_rect.right = gxdisplayprop.cxWidth;
700         display_rect.bottom = gxdisplayprop.cyHeight;
701
702         if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
703         {
704             return VLC_EGENERIC;
705         }
706
707 #if 0
708         msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
709                  "dest (%d,%d,%d,%d)",
710                  video_rect.left, video_rect.right,
711                  video_rect.top, video_rect.bottom,
712                  display_rect.left, display_rect.right,
713                  display_rect.top, display_rect.bottom,
714                  dest_rect.left, dest_rect.right,
715                  dest_rect.top, dest_rect.bottom );
716 #endif
717
718         if( !(p_dest = GXBeginDraw()) )
719         {
720 #if 0
721             msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
722 #endif
723             return VLC_EGENERIC;
724         }
725
726         p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
727             (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
728         p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
729             dest_rect.top * gxdisplayprop.cbyPitch;
730         i_width = dest_rect.right - dest_rect.left;
731         i_height = dest_rect.bottom - dest_rect.top;
732
733         p_pic->p->p_pixels = p_dest;
734     }
735
736     return VLC_SUCCESS;
737 }
738
739 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
740 {
741     GXEndDraw();
742     return VLC_SUCCESS;
743 }
744
745 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
746 {
747 }
748 #endif
749
750 #undef rect_src
751 #undef rect_src_clipped
752 #undef rect_dest
753 #undef rect_dest_clipped
754 /*****************************************************************************
755  * SetPalette: sets an 8 bpp palette
756  *****************************************************************************/
757 static void SetPalette( vout_thread_t *p_vout,
758                         uint16_t *red, uint16_t *green, uint16_t *blue )
759 {
760     msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
761 }
762
763 /*****************************************************************************
764  * EventThread: Event handling thread
765  *****************************************************************************/
766 static void EventThread ( vlc_object_t *p_event )
767 {
768     vout_thread_t *p_vout;
769     vlc_value_t   val;
770
771     int        i_style;
772     WNDCLASS   wc;
773     MSG        msg;
774
775     /* Initialisations */
776     var_Get( p_event, "p_vout", &val );
777     p_vout = (vout_thread_t *)val.p_address;
778
779     /* Register window class */
780     memset( &wc, 0, sizeof(wc) );
781     wc.style          = CS_HREDRAW | CS_VREDRAW;
782     wc.lpfnWndProc    = (WNDPROC)WndProc;
783     wc.cbClsExtra     = 0;
784     wc.cbWndExtra     = 0;
785     wc.hInstance      = GetModuleHandle(NULL);
786     wc.hIcon          = 0;
787     wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
788     wc.hbrBackground  = (HBRUSH)GetStockObject( BLACK_BRUSH );
789     wc.lpszMenuName   = 0;
790     wc.lpszClassName  = _T("VLC WinGDI");
791     RegisterClass( &wc );
792
793     /* Register the video sub-window class */
794     wc.lpszClassName = _T("VLC WinGDI video"); wc.hIcon = 0;
795     RegisterClass(&wc);
796
797     /* Create output window */
798     p_vout->p_sys->hparent = (HWND)
799         vout_RequestWindow( p_vout, &p_vout->p_sys->i_window_x,
800                             &p_vout->p_sys->i_window_y,
801                             (unsigned int *)&p_vout->p_sys->i_window_width,
802                             (unsigned int *)&p_vout->p_sys->i_window_height );
803
804     if( p_vout->p_sys->hparent )
805         ShowWindow( p_vout->p_sys->hparent, SW_SHOW );
806
807     if( p_vout->p_sys->hparent )
808         i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
809     else
810         i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
811
812     p_vout->p_sys->i_window_style = i_style;
813
814     p_vout->p_sys->hwnd =
815         CreateWindow( _T("VLC WinGDI"), _T(VOUT_TITLE), i_style,
816                       (p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
817                       p_vout->p_sys->i_window_x,   /* default X coordinate */
818                       (p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
819                       p_vout->p_sys->i_window_y,   /* default Y coordinate */
820                       p_vout->p_sys->i_window_width,
821                       p_vout->p_sys->i_window_height + 10,
822                       p_vout->p_sys->hparent, NULL,
823                       GetModuleHandle(NULL), (LPVOID)p_vout );
824
825     if( !p_vout->p_sys->hwnd )
826     {
827         msg_Warn( p_vout, "couldn't create window" );
828         return;
829     }
830     msg_Warn( p_vout, "Created WinGDI window" );
831
832     if( p_vout->p_sys->hparent )
833     {
834         LONG i_style;
835
836         /* We don't want the window owner to overwrite our client area */
837         i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
838
839         if( !(i_style & WS_CLIPCHILDREN) )
840             /* Hmmm, apparently this is a blocking call... */
841             SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
842                            i_style | WS_CLIPCHILDREN );
843
844         /* Create our fullscreen window */
845         p_vout->p_sys->hfswnd =
846             CreateWindowEx( WS_EX_APPWINDOW, _T("VLC WinGDI"),
847                             _T(VOUT_TITLE),
848                             WS_NONAVDONEBUTTON|WS_CLIPCHILDREN,
849                             CW_USEDEFAULT, CW_USEDEFAULT,
850                             CW_USEDEFAULT, CW_USEDEFAULT,
851                             NULL, NULL, GetModuleHandle(NULL), (LPVOID)p_vout);
852     }
853
854     /* Display our window */
855     ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
856     UpdateWindow( p_vout->p_sys->hwnd );
857
858     /* Create video sub-window */
859     p_vout->p_sys->hvideownd =
860         CreateWindow( _T("VLC WinGDI video"), _T(""),   /* window class */
861                     WS_CHILD | WS_VISIBLE,                   /* window style */
862                     CW_USEDEFAULT, CW_USEDEFAULT,     /* default coordinates */
863                     CW_USEDEFAULT, CW_USEDEFAULT,
864                     p_vout->p_sys->hwnd,                  /* parent window */
865                     NULL, GetModuleHandle(NULL),
866                     (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
867
868     /* Initialize offscreen buffer */
869     InitBuffers( p_vout );
870
871     p_vout->pf_control = Control;
872
873     /* Tell the video output we're ready to receive data */
874     vlc_thread_ready( p_event );
875
876     while( !p_event->b_die && GetMessage( &msg, 0, 0, 0 ) )
877     {
878         /* Check if we are asked to exit */
879         if( p_event->b_die ) break;
880
881         switch( msg.message )
882         {
883         case WM_KEYDOWN:
884             switch( msg.wParam )
885             {
886             case VK_ESCAPE:
887                 p_event->p_libvlc->b_die = VLC_TRUE;
888                 break;
889             }
890             TranslateMessage( &msg );
891             break;
892
893         case WM_CHAR:
894             switch( msg.wParam )
895             {
896             case 'q':
897             case 'Q':
898                 p_event->p_libvlc->b_die = VLC_TRUE;
899                 break;
900             }
901             break;
902
903         default:
904             TranslateMessage( &msg );
905             DispatchMessage( &msg );
906             break;
907         }
908     }
909
910     msg_Dbg( p_vout, "CloseWindow" );
911
912 #ifdef MODULE_NAME_IS_wingapi
913     GXCloseDisplay();
914 #else
915     DeleteDC( p_vout->p_sys->off_dc );
916     DeleteObject( p_vout->p_sys->off_bitmap );
917 #endif
918
919     DestroyWindow( p_vout->p_sys->hwnd );
920     if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
921
922     if( p_vout->p_sys->hparent )
923         vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
924 }
925
926 /*****************************************************************************
927  * UpdateRects: update clipping rectangles
928  *****************************************************************************
929  * This function is called when the window position or size are changed, and
930  * its job is to update the source and destination RECTs used to display the
931  * picture.
932  *****************************************************************************/
933 static void UpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
934 {
935 #define rect_src p_vout->p_sys->rect_src
936 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
937 #define rect_dest p_vout->p_sys->rect_dest
938 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
939
940     int i_width, i_height, i_x, i_y;
941
942     RECT  rect;
943     POINT point;
944
945     /* Retrieve the window size */
946     GetClientRect( p_vout->p_sys->hwnd, &rect );
947
948     /* Retrieve the window position */
949     point.x = point.y = 0;
950     ClientToScreen( p_vout->p_sys->hwnd, &point );
951
952     /* If nothing changed, we can return */
953     if( !b_force
954          && p_vout->p_sys->i_window_width == rect.right
955          && p_vout->p_sys->i_window_height == rect.bottom
956          && p_vout->p_sys->i_window_x == point.x
957          && p_vout->p_sys->i_window_y == point.y )
958     {
959         return;
960     }
961
962     /* Update the window position and size */
963     p_vout->p_sys->i_window_x = point.x;
964     p_vout->p_sys->i_window_y = point.y;
965     p_vout->p_sys->i_window_width = rect.right;
966     p_vout->p_sys->i_window_height = rect.bottom;
967
968     vout_PlacePicture( p_vout, rect.right, rect.bottom,
969                        &i_x, &i_y, &i_width, &i_height );
970
971     if( p_vout->p_sys->hvideownd )
972         SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
973                       i_x, i_y, i_width, i_height, 0 );
974
975     /* Destination image position and dimensions */
976     rect_dest.left = point.x + i_x;
977     rect_dest.right = rect_dest.left + i_width;
978     rect_dest.top = point.y + i_y;
979     rect_dest.bottom = rect_dest.top + i_height;
980
981     /* Clip the destination window */
982     if( !IntersectRect( &rect_dest_clipped, &rect_dest,
983                         &p_vout->p_sys->rect_display ) )
984     {
985         SetRectEmpty( &rect_src_clipped );
986         return;
987     }
988
989 #if 0
990     msg_Dbg( p_vout, "image_dst_clipped coords: %i,%i,%i,%i",
991                      rect_dest_clipped.left, rect_dest_clipped.top,
992                      rect_dest_clipped.right, rect_dest_clipped.bottom );
993 #endif
994
995     /* the 2 following lines are to fix a bug when clicking on the desktop */
996     if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
997         (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
998     {
999         SetRectEmpty( &rect_src_clipped );
1000         return;
1001     }
1002
1003     /* src image dimensions */
1004     rect_src.left = 0;
1005     rect_src.top = 0;
1006     rect_src.right = p_vout->output.i_width;
1007     rect_src.bottom = p_vout->output.i_height;
1008
1009     /* Clip the source image */
1010     rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
1011       p_vout->output.i_width / (rect_dest.right - rect_dest.left);
1012     rect_src_clipped.right = p_vout->output.i_width -
1013       (rect_dest.right - rect_dest_clipped.right) * p_vout->output.i_width /
1014       (rect_dest.right - rect_dest.left);
1015     rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
1016       p_vout->output.i_height / (rect_dest.bottom - rect_dest.top);
1017     rect_src_clipped.bottom = p_vout->output.i_height -
1018       (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->output.i_height /
1019       (rect_dest.bottom - rect_dest.top);
1020
1021 #if 0
1022     msg_Dbg( p_vout, "image_src_clipped coords: %i,%i,%i,%i",
1023                      rect_src_clipped.left, rect_src_clipped.top,
1024                      rect_src_clipped.right, rect_src_clipped.bottom );
1025 #endif
1026
1027     /* The destination coordinates need to be relative to the current
1028      * directdraw primary surface (display) */
1029     rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
1030     rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
1031     rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
1032     rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
1033
1034     /* Signal the change in size/position */
1035     p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
1036
1037 #undef rect_src
1038 #undef rect_src_clipped
1039 #undef rect_dest
1040 #undef rect_dest_clipped
1041 }
1042
1043 /*****************************************************************************
1044  * Message handler for the main window
1045  *****************************************************************************/
1046 static long FAR PASCAL WndProc( HWND hWnd, UINT message,
1047                                 WPARAM wParam, LPARAM lParam )
1048 {
1049     vout_thread_t *p_vout;
1050
1051     if( message == WM_CREATE )
1052     {
1053         /* Store p_vout for future use */
1054         p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
1055         SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)p_vout );
1056         if( p_vout ) msg_Dbg( p_vout, "create: %p", hWnd );
1057     }
1058     else
1059     {
1060         p_vout = (vout_thread_t *)GetWindowLongPtr( hWnd, GWLP_USERDATA );
1061     }
1062
1063 #ifndef UNDER_CE
1064     /* Catch the screensaver and the monitor turn-off */
1065     if( message == WM_SYSCOMMAND &&
1066         ( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
1067     {
1068         //if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
1069         return 0; /* this stops them from happening */
1070     }
1071 #endif
1072
1073     if( !p_vout )
1074     {
1075         /* Hmmm mozilla does manage somehow to save the pointer to our
1076          * windowproc and still calls it after the vout has been closed. */
1077         return DefWindowProc(hWnd, message, wParam, lParam);
1078     }
1079
1080     if( hWnd != p_vout->p_sys->hwnd &&
1081         hWnd != p_vout->p_sys->hfswnd &&
1082         hWnd != p_vout->p_sys->hvideownd )
1083         return DefWindowProc(hWnd, message, wParam, lParam);
1084
1085     switch( message )
1086     {
1087     case WM_WINDOWPOSCHANGED:
1088         if( hWnd == p_vout->p_sys->hwnd )
1089             UpdateRects( p_vout, VLC_TRUE );
1090         break;
1091
1092 #if 0
1093     case WM_ACTIVATE:
1094         msg_Err( p_vout, "WM_ACTIVATE: %i", wParam );
1095         if( wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE )
1096             GXResume();
1097         else if( wParam == WA_INACTIVE )
1098             GXSuspend();
1099         break;
1100 #endif
1101
1102     case WM_KILLFOCUS:
1103         p_vout->p_sys->b_focus = VLC_FALSE;
1104         if( !p_vout->p_sys->b_parent_focus ) GXSuspend();
1105
1106         if( hWnd == p_vout->p_sys->hfswnd )
1107         {
1108 #ifdef UNDER_CE
1109             HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
1110             ShowWindow( htbar, SW_SHOW );
1111 #endif
1112         }
1113
1114         if( !p_vout->p_sys->hparent ||
1115             hWnd == p_vout->p_sys->hfswnd )
1116         {
1117             SHFullScreen( hWnd, SHFS_SHOWSIPBUTTON );
1118         }
1119         break;
1120
1121     case WM_SETFOCUS:
1122         p_vout->p_sys->b_focus = VLC_TRUE;
1123         GXResume();
1124
1125         if( p_vout->p_sys->hparent &&
1126             hWnd != p_vout->p_sys->hfswnd && p_vout->b_fullscreen )
1127             p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
1128
1129         if( hWnd == p_vout->p_sys->hfswnd )
1130         {
1131 #ifdef UNDER_CE
1132             HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
1133             ShowWindow( htbar, SW_HIDE );
1134 #endif
1135         }
1136
1137         if( !p_vout->p_sys->hparent ||
1138             hWnd == p_vout->p_sys->hfswnd )
1139         {
1140             SHFullScreen( hWnd, SHFS_HIDESIPBUTTON );
1141         }
1142         break;
1143
1144     case WM_LBUTTONDOWN:
1145         p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
1146         break;
1147     case WM_MOUSEMOVE:
1148         break;
1149     case WM_LBUTTONUP:
1150         break;
1151
1152     case WM_INITMENUPOPUP:
1153         p_vout->p_sys->b_video_display = VLC_FALSE;
1154         break;
1155
1156     case WM_NOTIFY:
1157         // Redo the video display because menu can be closed
1158         // FIXME verify if p_child_window exits
1159         if( (((NMHDR *)lParam)->code) == NM_CUSTOMDRAW )
1160             p_vout->p_sys->b_video_display = VLC_TRUE;
1161         break;
1162
1163     /* the user wants to close the window */
1164     case WM_CLOSE:
1165     {
1166         playlist_t * p_playlist =
1167             (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1168                                            FIND_ANYWHERE );
1169         if( p_playlist == NULL ) return 0;
1170
1171         playlist_Stop( p_playlist );
1172         vlc_object_release( p_playlist );
1173         return 0;
1174     }
1175
1176     case WM_DESTROY:
1177         msg_Dbg( p_vout, "WinProc WM_DESTROY" );
1178         PostQuitMessage( 0 );
1179         break;
1180
1181     default:
1182         return DefWindowProc( hWnd, message, wParam, lParam );
1183     }
1184
1185     return 0;
1186 }
1187
1188 /*****************************************************************************
1189  * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
1190  *****************************************************************************/
1191 static void InitBuffers( vout_thread_t *p_vout )
1192 {
1193     BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
1194     BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
1195     int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
1196     HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
1197
1198     /* Get screen properties */
1199 #ifdef MODULE_NAME_IS_wingapi
1200     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
1201     p_vout->p_sys->i_depth = gx_displayprop.cBPP;
1202 #else
1203     p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
1204         GetDeviceCaps( window_dc, BITSPIXEL );
1205 #endif
1206     msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
1207
1208 #ifdef MODULE_NAME_IS_wingapi
1209     GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
1210
1211 #else
1212
1213     /* Initialize offscreen bitmap */
1214     memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
1215
1216     p_header->biSize = sizeof( BITMAPINFOHEADER );
1217     p_header->biSizeImage = 0;
1218     p_header->biPlanes = 1;
1219     switch( p_vout->p_sys->i_depth )
1220     {
1221     case 8:
1222         p_header->biBitCount = 8;
1223         p_header->biCompression = BI_RGB;
1224         /* FIXME: we need a palette here */
1225         break;
1226     case 15:
1227         p_header->biBitCount = 15;
1228         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
1229         ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
1230         ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
1231         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
1232         break;
1233     case 16:
1234         p_header->biBitCount = 16;
1235         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
1236         ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
1237         ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
1238         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
1239         break;
1240     case 24:
1241         p_header->biBitCount = 24;
1242         p_header->biCompression = BI_RGB;
1243         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
1244         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
1245         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
1246         break;
1247     case 32:
1248         p_header->biBitCount = 32;
1249         p_header->biCompression = BI_RGB;
1250         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
1251         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
1252         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
1253         break;
1254     default:
1255         msg_Err( p_vout, "screen depth %i not supported",
1256                  p_vout->p_sys->i_depth );
1257         return;
1258         break;
1259     }
1260     p_header->biWidth = p_vout->render.i_width;
1261     p_header->biHeight = -p_vout->render.i_height;
1262     p_header->biClrImportant = 0;
1263     p_header->biClrUsed = 0;
1264     p_header->biXPelsPerMeter = 0;
1265     p_header->biYPelsPerMeter = 0;
1266
1267     p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
1268     p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
1269
1270     p_vout->p_sys->off_bitmap =
1271         CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
1272                           (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
1273
1274     p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
1275
1276     SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
1277     ReleaseDC( 0, window_dc );
1278 #endif
1279 }
1280
1281 /*****************************************************************************
1282  * Control: control facility for the vout
1283  *****************************************************************************/
1284 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
1285 {
1286     unsigned int *pi_width, *pi_height;
1287     vlc_bool_t b_bool;
1288     RECT rect_window;
1289     POINT point;
1290
1291     switch( i_query )
1292     {
1293     case VOUT_GET_SIZE:
1294         if( p_vout->p_sys->hparent )
1295             return vout_ControlWindow( p_vout,
1296                     (void *)p_vout->p_sys->hparent, i_query, args );
1297
1298         pi_width  = va_arg( args, unsigned int * );
1299         pi_height = va_arg( args, unsigned int * );
1300
1301         GetClientRect( p_vout->p_sys->hwnd, &rect_window );
1302
1303         *pi_width  = rect_window.right - rect_window.left;
1304         *pi_height = rect_window.bottom - rect_window.top;
1305         return VLC_SUCCESS;
1306
1307     case VOUT_SET_SIZE:
1308         if( p_vout->p_sys->hparent )
1309             return vout_ControlWindow( p_vout,
1310                     (void *)p_vout->p_sys->hparent, i_query, args );
1311
1312         /* Update dimensions */
1313         rect_window.top = rect_window.left = 0;
1314         rect_window.right  = va_arg( args, unsigned int );
1315         rect_window.bottom = va_arg( args, unsigned int );
1316         if( !rect_window.right ) rect_window.right = p_vout->i_window_width;
1317         if( !rect_window.bottom ) rect_window.bottom = p_vout->i_window_height;
1318         AdjustWindowRect( &rect_window, p_vout->p_sys->i_window_style, 0 );
1319
1320         SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
1321                       rect_window.right - rect_window.left,
1322                       rect_window.bottom - rect_window.top, SWP_NOMOVE );
1323
1324         return VLC_SUCCESS;
1325
1326     case VOUT_CLOSE:
1327         ShowWindow( p_vout->p_sys->hwnd, SW_HIDE );
1328     case VOUT_REPARENT:
1329         /* Change window style, borders and title bar */
1330         //vlc_mutex_lock( &p_vout->p_sys->lock );
1331         p_vout->p_sys->hparent = 0;
1332         //vlc_mutex_unlock( &p_vout->p_sys->lock );
1333
1334         /* Retrieve the window position */
1335         point.x = point.y = 0;
1336         ClientToScreen( p_vout->p_sys->hwnd, &point );
1337
1338         SetParent( p_vout->p_sys->hwnd, 0 );
1339         p_vout->p_sys->i_window_style =
1340             WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
1341         SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
1342                        p_vout->p_sys->i_window_style |
1343                        (i_query == VOUT_CLOSE ? 0 : WS_VISIBLE) );
1344         SetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW );
1345         SetWindowPos( p_vout->p_sys->hwnd, 0, point.x, point.y, 0, 0,
1346                       SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
1347
1348         return vout_vaControlDefault( p_vout, i_query, args );
1349
1350     case VOUT_SET_FOCUS:
1351         b_bool = va_arg( args, vlc_bool_t );
1352
1353         p_vout->p_sys->b_parent_focus = b_bool;
1354         if( b_bool ) GXResume();
1355         else if( !p_vout->p_sys->b_focus ) GXSuspend();
1356
1357         return VLC_SUCCESS;
1358
1359     default:
1360         return vout_vaControlDefault( p_vout, i_query, args );
1361     }
1362 }