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