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