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