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