]> git.sesse.net Git - vlc/blob - modules/video_output/msw/wingdi.c
Remove stdlib.h
[vlc] / modules / video_output / msw / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 the VideoLAN team
5  * $Id: wingdi.c 18074 2006-11-26 16:26:44Z zorglub $
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 <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_interface.h>
32 #include <vlc_playlist.h>
33 #include <vlc_vout.h>
34
35 #include <commctrl.h>
36
37 #include "vout.h"
38
39 #ifdef MODULE_NAME_IS_wingapi
40     typedef struct GXDisplayProperties {
41         DWORD cxWidth;
42         DWORD cyHeight;
43         long cbxPitch;
44         long cbyPitch;
45         long cBPP;
46         DWORD ffFormat;
47     } GXDisplayProperties;
48
49     typedef struct GXScreenRect {
50         DWORD dwTop;
51         DWORD dwLeft;
52         DWORD dwWidth;
53         DWORD dwHeight;
54     } GXScreenRect;
55
56 #   define GX_FULLSCREEN    0x01
57 #   define GX_NORMALKEYS    0x02
58 #   define GX_LANDSCAPEKEYS 0x03
59
60 #   ifndef kfLandscape
61 #       define kfLandscape      0x8
62 #       define kfPalette        0x10
63 #       define kfDirect         0x20
64 #       define kfDirect555      0x40
65 #       define kfDirect565      0x80
66 #       define kfDirect888      0x100
67 #       define kfDirect444      0x200
68 #       define kfDirectInverted 0x400
69 #   endif
70 #endif /* MODULE_NAME_IS_wingapi */
71
72 #define MAX_DIRECTBUFFERS 10
73
74 #ifdef UNDER_CE
75 #ifndef WS_OVERLAPPEDWINDOW
76 #   define WS_OVERLAPPEDWINDOW 0xcf0000
77 #endif
78 #ifndef WS_EX_NOPARENTNOTIFY
79 #   define WS_EX_NOPARENTNOTIFY 4
80 #endif
81 #ifndef WS_EX_APPWINDOW
82 #define WS_EX_APPWINDOW 0x40000
83 #endif
84 #define SetWindowLongPtr SetWindowLong
85 #define GetWindowLongPtr GetWindowLong
86 #define GWLP_USERDATA GWL_USERDATA
87 #define AdjustWindowRect(a,b,c)
88 #endif //UNDER_CE
89
90 #ifndef WS_NONAVDONEBUTTON
91 #define WS_NONAVDONEBUTTON 0
92 #endif
93 /*****************************************************************************
94  * Local prototypes
95  *****************************************************************************/
96 static int  OpenVideo  ( vlc_object_t * );
97 static void CloseVideo ( vlc_object_t * );
98
99 static int  Init      ( vout_thread_t * );
100 static void End       ( vout_thread_t * );
101 static int  Manage    ( vout_thread_t * );
102 static void Render    ( vout_thread_t *, picture_t * );
103 #ifdef MODULE_NAME_IS_wingapi
104 static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
105 static void DisplayGAPI( vout_thread_t *, picture_t * );
106 static int GAPILockSurface( vout_thread_t *, picture_t * );
107 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
108 #else
109 static void FirstDisplayGDI( vout_thread_t *, picture_t * );
110 static void DisplayGDI( vout_thread_t *, picture_t * );
111 #endif
112 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
113
114 static void InitBuffers        ( vout_thread_t * );
115
116 #ifdef MODULE_NAME_IS_wingapi
117 #   define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
118 #   define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
119 #   define GXBeginDraw p_vout->p_sys->GXBeginDraw
120 #   define GXEndDraw p_vout->p_sys->GXEndDraw
121 #   define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
122 #   define GXSuspend p_vout->p_sys->GXSuspend
123 #   define GXResume p_vout->p_sys->GXResume
124 #endif
125
126 #define DX_POSITION_CHANGE 0x1000
127
128 /*****************************************************************************
129  * Module descriptor
130  *****************************************************************************/
131 vlc_module_begin();
132     set_category( CAT_VIDEO );
133     set_subcategory( SUBCAT_VIDEO_VOUT );
134 #ifdef MODULE_NAME_IS_wingapi
135     set_shortname( "Windows GAPI" );
136     set_description( _("Windows GAPI video output") );
137     set_capability( "video output", 20 );
138 #else
139     set_shortname( "Windows GDI" );
140     set_description( _("Windows GDI video output") );
141     set_capability( "video output", 10 );
142 #endif
143     set_callbacks( OpenVideo, CloseVideo );
144 vlc_module_end();
145
146 /*****************************************************************************
147  * OpenVideo: activate GDI video thread output method
148  *****************************************************************************/
149 static int OpenVideo ( vlc_object_t *p_this )
150 {
151     vout_thread_t * p_vout = (vout_thread_t *)p_this;
152     vlc_value_t val;
153
154     p_vout->p_sys = (vout_sys_t *)malloc( sizeof(vout_sys_t) );
155     if( !p_vout->p_sys ) return VLC_ENOMEM;
156     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
157
158 #ifdef MODULE_NAME_IS_wingapi
159     /* Load GAPI */
160     p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
161     if( p_vout->p_sys->gapi_dll == NULL )
162     {
163         msg_Warn( p_vout, "failed loading gx.dll" );
164         free( p_vout->p_sys );
165         return VLC_EGENERIC;
166     }
167
168     GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
169         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
170     GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
171         _T("?GXCloseDisplay@@YAHXZ") );
172     GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
173         _T("?GXBeginDraw@@YAPAXXZ") );
174     GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
175         _T("?GXEndDraw@@YAHXZ") );
176     GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
177         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
178     GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
179         _T("?GXSuspend@@YAHXZ") );
180     GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
181         _T("?GXResume@@YAHXZ") );
182
183     if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
184         !GXGetDisplayProperties || !GXSuspend || !GXResume )
185     {
186         msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
187         free( p_vout->p_sys );
188         return VLC_EGENERIC;
189     }
190
191     msg_Dbg( p_vout, "GAPI DLL loaded" );
192
193     p_vout->p_sys->render_width = p_vout->render.i_width;
194     p_vout->p_sys->render_height = p_vout->render.i_height;
195 #endif
196
197     p_vout->p_sys->p_event = (vlc_object_t *)
198         vlc_object_create( p_vout, VLC_OBJECT_GENERIC );
199     if( !p_vout->p_sys->p_event )
200     {
201         free( p_vout->p_sys );
202         return VLC_ENOMEM;
203     }
204
205     p_vout->pf_init = Init;
206     p_vout->pf_end = End;
207     p_vout->pf_manage = Manage;
208     p_vout->pf_render = Render;
209 #ifdef MODULE_NAME_IS_wingapi
210     p_vout->pf_display = FirstDisplayGAPI;
211
212     p_vout->p_sys->b_focus = 0;
213     p_vout->p_sys->b_parent_focus = 0;
214
215 #else
216     p_vout->pf_display = FirstDisplayGDI;
217 #endif
218
219     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
220     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
221     p_vout->p_sys->i_changes = 0;
222     vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
223     SetRectEmpty( &p_vout->p_sys->rect_display );
224     SetRectEmpty( &p_vout->p_sys->rect_parent );
225
226     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
227     var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
228
229     p_vout->p_sys->b_cursor_hidden = 0;
230     p_vout->p_sys->i_lastmoved = mdate();
231
232     /* Set main window's size */
233     p_vout->p_sys->i_window_width = p_vout->i_window_width;
234     p_vout->p_sys->i_window_height = p_vout->i_window_height;
235
236     /* Create the EventThread, this thread is created by us to isolate
237      * the Win32 PeekMessage function calls. We want to do this because
238      * Windows can stay blocked inside this call for a long time, and when
239      * this happens it thus blocks vlc's video_output thread.
240      * Vout EventThread will take care of the creation of the video
241      * window (because PeekMessage has to be called from the same thread which
242      * created the window). */
243     msg_Dbg( p_vout, "creating Vout EventThread" );
244     p_vout->p_sys->p_event =
245         vlc_object_create( p_vout, sizeof(event_thread_t) );
246     p_vout->p_sys->p_event->p_vout = p_vout;
247     if( vlc_thread_create( p_vout->p_sys->p_event, "VLC Vout Events Thread",
248                            E_(EventThread), 0, 1 ) )
249     {
250         msg_Err( p_vout, "cannot create Vout EventThread" );
251         vlc_object_destroy( p_vout->p_sys->p_event );
252         p_vout->p_sys->p_event = NULL;
253         goto error;
254     }
255
256     if( p_vout->p_sys->p_event->b_error )
257     {
258         msg_Err( p_vout, "Vout EventThread failed" );
259         goto error;
260     }
261
262     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
263
264     msg_Dbg( p_vout, "Vout EventThread running" );
265
266 #ifndef UNDER_CE
267     /* Variable to indicate if the window should be on top of others */
268     /* Trigger a callback right now */
269     var_Get( p_vout, "video-on-top", &val );
270     var_Set( p_vout, "video-on-top", val );
271
272     /* disable screensaver by temporarily changing system settings */
273     p_vout->p_sys->i_spi_lowpowertimeout = 0;
274     p_vout->p_sys->i_spi_powerofftimeout = 0;
275     p_vout->p_sys->i_spi_screensavetimeout = 0;
276     var_Get( p_vout, "disable-screensaver", &val);
277     if( val.b_bool ) {
278         msg_Dbg(p_vout, "disabling screen saver");
279         SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
280             0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
281         if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
282             SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
283         }
284         SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
285             &(p_vout->p_sys->i_spi_powerofftimeout), 0);
286         if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
287             SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
288         }
289         SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
290             &(p_vout->p_sys->i_spi_screensavetimeout), 0);
291         if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
292             SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
293         }
294     }
295 #endif
296     return VLC_SUCCESS;
297
298 error:
299     CloseVideo( VLC_OBJECT(p_vout) );
300     return VLC_EGENERIC;
301 }
302
303 /*****************************************************************************
304  * CloseVideo: deactivate the GDI video output
305  *****************************************************************************/
306 static void CloseVideo ( vlc_object_t *p_this )
307 {
308     vout_thread_t * p_vout = (vout_thread_t *)p_this;
309
310     if( p_vout->p_sys->p_event )
311     {
312         vlc_object_detach( p_vout->p_sys->p_event );
313
314         /* Kill Vout EventThread */
315         vlc_object_kill( p_vout->p_sys->p_event );
316
317         /* we need to be sure Vout EventThread won't stay stuck in
318          * GetMessage, so we send a fake message */
319         if( p_vout->p_sys->hwnd )
320         {
321             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
322         }
323
324         vlc_thread_join( p_vout->p_sys->p_event );
325         vlc_object_destroy( p_vout->p_sys->p_event );
326     }
327     vlc_mutex_destroy( &p_vout->p_sys->lock );
328
329 #ifndef UNDER_CE
330     /* restore screensaver system settings */
331     if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
332         SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
333             p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
334     }
335     if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
336         SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
337             p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
338     }
339     if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
340         SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
341             p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
342     }
343 #endif
344
345 #ifdef MODULE_NAME_IS_wingapi
346     FreeLibrary( p_vout->p_sys->gapi_dll );
347 #endif
348
349     if( p_vout->p_sys )
350     {
351         free( p_vout->p_sys );
352         p_vout->p_sys = NULL;
353     }
354 }
355
356 /*****************************************************************************
357  * Init: initialize video thread output method
358  *****************************************************************************/
359 static int Init( vout_thread_t *p_vout )
360 {
361     picture_t *p_pic;
362
363     /* Initialize offscreen buffer */
364     InitBuffers( p_vout );
365
366     p_vout->p_sys->rect_display.left = 0;
367     p_vout->p_sys->rect_display.top = 0;
368     p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
369     p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
370
371     I_OUTPUTPICTURES = 0;
372
373     /* Initialize the output structure */
374     switch( p_vout->p_sys->i_depth )
375     {
376     case 8:
377         p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
378         p_vout->output.pf_setpalette = SetPalette;
379         break;
380     case 15:
381         p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
382         p_vout->output.i_rmask  = 0x7c00;
383         p_vout->output.i_gmask  = 0x03e0;
384         p_vout->output.i_bmask  = 0x001f;
385         break;
386     case 16:
387         p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
388         p_vout->output.i_rmask  = 0xf800;
389         p_vout->output.i_gmask  = 0x07e0;
390         p_vout->output.i_bmask  = 0x001f;
391         break;
392     case 24:
393         p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
394         p_vout->output.i_rmask  = 0x00ff0000;
395         p_vout->output.i_gmask  = 0x0000ff00;
396         p_vout->output.i_bmask  = 0x000000ff;
397         break;
398     case 32:
399         p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
400         p_vout->output.i_rmask  = 0x00ff0000;
401         p_vout->output.i_gmask  = 0x0000ff00;
402         p_vout->output.i_bmask  = 0x000000ff;
403         break;
404     default:
405         msg_Err( p_vout, "screen depth %i not supported",
406                  p_vout->p_sys->i_depth );
407         return VLC_EGENERIC;
408         break;
409     }
410
411     p_pic = &p_vout->p_picture[0];
412
413 #ifdef MODULE_NAME_IS_wingapi
414     p_vout->output.i_width  = 0;
415     p_vout->output.i_height = 0;
416     p_pic->pf_lock  = GAPILockSurface;
417     p_pic->pf_unlock = GAPIUnlockSurface;
418     Manage( p_vout );
419     GAPILockSurface( p_vout, p_pic );
420     p_vout->i_changes = 0;
421     p_vout->output.i_width  = p_vout->p_sys->render_width;
422     p_vout->output.i_height = p_vout->p_sys->render_height;
423
424 #else
425     p_vout->output.i_width  = p_vout->render.i_width;
426     p_vout->output.i_height = p_vout->render.i_height;
427
428     p_vout->fmt_out = p_vout->fmt_in;
429     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
430 #endif
431
432     p_vout->output.i_aspect = p_vout->render.i_aspect;
433
434     p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
435     p_pic->p->i_lines = p_vout->output.i_height;
436     p_pic->p->i_visible_lines = p_vout->output.i_height;
437     p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
438     p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
439     p_pic->p->i_visible_pitch = p_vout->output.i_width *
440         p_pic->p->i_pixel_pitch;
441     p_pic->i_planes = 1;
442     p_pic->i_status = DESTROYED_PICTURE;
443     p_pic->i_type   = DIRECT_PICTURE;
444
445     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
446
447     /* Change the window title bar text */
448     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
449     E_(UpdateRects)( p_vout, VLC_TRUE );
450
451     return VLC_SUCCESS;
452 }
453
454 /*****************************************************************************
455  * End: terminate video thread output method
456  *****************************************************************************/
457 static void End( vout_thread_t *p_vout )
458 {
459 #ifdef MODULE_NAME_IS_wingapi
460     GXCloseDisplay();
461 #else
462     DeleteDC( p_vout->p_sys->off_dc );
463     DeleteObject( p_vout->p_sys->off_bitmap );
464 #endif
465 }
466
467 /*****************************************************************************
468  * Manage: handle events
469  *****************************************************************************
470  * This function should be called regularly by video output thread. It manages
471  * console events. It returns a non null value on error.
472  *****************************************************************************/
473 static int Manage( vout_thread_t *p_vout )
474 {
475     /* If we do not control our window, we check for geometry changes
476      * ourselves because the parent might not send us its events. */
477     vlc_mutex_lock( &p_vout->p_sys->lock );
478     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
479     {
480         RECT rect_parent;
481         POINT point;
482
483         vlc_mutex_unlock( &p_vout->p_sys->lock );
484
485         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
486         point.x = point.y = 0;
487         ClientToScreen( p_vout->p_sys->hparent, &point );
488         OffsetRect( &rect_parent, point.x, point.y );
489
490         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
491         {
492             int i_x, i_y, i_width, i_height;
493             p_vout->p_sys->rect_parent = rect_parent;
494
495             /* This one is to force the update even if only
496              * the position has changed */
497             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
498                           rect_parent.right - rect_parent.left,
499                           rect_parent.bottom - rect_parent.top, 0 );
500
501             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
502                           rect_parent.right - rect_parent.left,
503                           rect_parent.bottom - rect_parent.top, 0 );
504
505             vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
506                                rect_parent.bottom - rect_parent.top,
507                                &i_x, &i_y, &i_width, &i_height );
508
509             SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
510                           i_x, i_y, i_width, i_height, 0 );
511         }
512     }
513     else
514     {
515         vlc_mutex_unlock( &p_vout->p_sys->lock );
516     }
517
518     /* Check for cropping / aspect changes */
519     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
520         p_vout->i_changes & VOUT_ASPECT_CHANGE )
521     {
522         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
523         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
524
525         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
526         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
527         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
528         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
529         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
530         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
531         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
532         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
533         E_(UpdateRects)( p_vout, VLC_TRUE );
534     }
535
536     /*
537      * Position Change
538      */
539     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
540     {
541         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
542     }
543
544     /* We used to call the Win32 PeekMessage function here to read the window
545      * messages. But since window can stay blocked into this function for a
546      * long time (for example when you move your window on the screen), I
547      * decided to isolate PeekMessage in another thread. */
548
549     /*
550      * Fullscreen change
551      */
552     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
553         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
554     {
555         Win32ToggleFullscreen( p_vout );
556
557         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
558         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
559     }
560
561     /*
562      * Pointer change
563      */
564     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
565         (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
566     {
567         POINT point;
568         HWND hwnd;
569
570         /* Hide the cursor only if it is inside our window */
571         GetCursorPos( &point );
572         hwnd = WindowFromPoint(point);
573         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
574         {
575             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
576         }
577         else
578         {
579             p_vout->p_sys->i_lastmoved = mdate();
580         }
581     }
582
583     /*
584      * "Always on top" status change
585      */
586     if( p_vout->p_sys->b_on_top_change )
587     {
588         vlc_value_t val;
589         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
590
591         var_Get( p_vout, "video-on-top", &val );
592
593         /* Set the window on top if necessary */
594         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
595                            & WS_EX_TOPMOST ) )
596         {
597             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
598                            MF_BYCOMMAND | MFS_CHECKED );
599             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
600                           SWP_NOSIZE | SWP_NOMOVE );
601         }
602         else
603         /* The window shouldn't be on top */
604         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
605                            & WS_EX_TOPMOST ) )
606         {
607             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
608                            MF_BYCOMMAND | MFS_UNCHECKED );
609             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
610                           SWP_NOSIZE | SWP_NOMOVE );
611         }
612
613         p_vout->p_sys->b_on_top_change = VLC_FALSE;
614     }
615
616     /* Check if the event thread is still running */
617     if( p_vout->p_sys->p_event->b_die )
618     {
619         return VLC_EGENERIC; /* exit */
620     }
621
622     return VLC_SUCCESS;
623 }
624
625 /*****************************************************************************
626  * Render: render previously calculated output
627  *****************************************************************************/
628 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
629 {
630     /* No need to do anything, the fake direct buffers stay as they are */
631 }
632
633 /*****************************************************************************
634  * Display: displays previously rendered output
635  *****************************************************************************/
636 #define rect_src p_vout->p_sys->rect_src
637 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
638 #define rect_dest p_vout->p_sys->rect_dest
639 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
640
641 #ifndef MODULE_NAME_IS_wingapi
642 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
643 {
644     vout_sys_t *p_sys = p_vout->p_sys;
645     RECT rect_dst = rect_dest_clipped;
646     HDC hdc = GetDC( p_sys->hvideownd );
647
648     OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
649     SelectObject( p_sys->off_dc, p_sys->off_bitmap );
650
651     if( rect_dest_clipped.right - rect_dest_clipped.left !=
652         rect_src_clipped.right - rect_src_clipped.left ||
653         rect_dest_clipped.bottom - rect_dest_clipped.top !=
654         rect_src_clipped.bottom - rect_src_clipped.top )
655     {
656         StretchBlt( hdc, rect_dst.left, rect_dst.top,
657                     rect_dst.right, rect_dst.bottom,
658                     p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
659                     rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
660     }
661     else
662     {
663         BitBlt( hdc, rect_dst.left, rect_dst.top,
664                 rect_dst.right, rect_dst.bottom,
665                 p_sys->off_dc, rect_src_clipped.left,
666                 rect_src_clipped.top, SRCCOPY );
667     }
668
669     ReleaseDC( p_sys->hvideownd, hdc );
670 }
671
672 static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
673 {
674     /*
675     ** Video window is initially hidden, show it now since we got a 
676     ** picture to show.
677     */
678     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0, 
679         SWP_ASYNCWINDOWPOS|
680         SWP_FRAMECHANGED|
681         SWP_SHOWWINDOW|
682         SWP_NOMOVE|
683         SWP_NOSIZE|
684         SWP_NOZORDER );
685
686     /* get initial picture presented */
687     DisplayGDI(p_vout, p_pic);
688
689     /* use and restores proper display function for further pictures */
690     p_vout->pf_display = DisplayGDI;
691 }
692
693 #else
694
695 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
696 {
697     vout_sys_t *p_sys = p_vout->p_sys;
698     int i_x, i_y, i_width, i_height;
699     RECT video_rect;
700     POINT point;
701
702     GetClientRect( p_sys->hwnd, &video_rect);
703     vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
704                        video_rect.bottom - video_rect.top,
705                        &i_x, &i_y, &i_width, &i_height );
706     point.x = point.y = 0;
707     ClientToScreen( p_sys->hwnd, &point );
708     i_x += point.x + video_rect.left;
709     i_y += point.y + video_rect.top;
710
711     if( i_width != p_vout->output.i_width ||
712         i_height != p_vout->output.i_height )
713     {
714         GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
715
716         p_sys->render_width = i_width;
717         p_sys->render_height = i_height;
718         p_vout->i_changes |= VOUT_SIZE_CHANGE;
719
720         msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
721                  i_width, i_height, p_vout->output.i_width,
722                  p_vout->output.i_height );
723
724         p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
725         p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
726         return VLC_EGENERIC;
727     }
728     else
729     {
730         GXDisplayProperties gxdisplayprop;
731         RECT display_rect, dest_rect;
732         uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
733
734         video_rect.left = i_x; video_rect.top = i_y;
735         video_rect.right = i_x + i_width;
736         video_rect.bottom = i_y + i_height;
737
738         gxdisplayprop = GXGetDisplayProperties();
739         display_rect.left = 0; display_rect.top = 0;
740         display_rect.right = gxdisplayprop.cxWidth;
741         display_rect.bottom = gxdisplayprop.cyHeight;
742
743         if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
744         {
745             return VLC_EGENERIC;
746         }
747
748 #if 0
749         msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
750                  "dest (%d,%d,%d,%d)",
751                  video_rect.left, video_rect.right,
752                  video_rect.top, video_rect.bottom,
753                  display_rect.left, display_rect.right,
754                  display_rect.top, display_rect.bottom,
755                  dest_rect.left, dest_rect.right,
756                  dest_rect.top, dest_rect.bottom );
757 #endif
758
759         if( !(p_dest = GXBeginDraw()) )
760         {
761 #if 0
762             msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
763 #endif
764             return VLC_EGENERIC;
765         }
766
767         p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
768             (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
769         p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
770             dest_rect.top * gxdisplayprop.cbyPitch;
771         i_width = dest_rect.right - dest_rect.left;
772         i_height = dest_rect.bottom - dest_rect.top;
773
774         p_pic->p->p_pixels = p_dest;
775     }
776
777     return VLC_SUCCESS;
778 }
779
780 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
781 {
782     GXEndDraw();
783     return VLC_SUCCESS;
784 }
785
786 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
787 {
788 }
789
790 static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
791 {
792     /* get initial picture presented through D3D */
793     DisplayGAPI(p_vout, p_pic);
794
795     /*
796     ** Video window is initially hidden, show it now since we got a 
797     ** picture to show.
798     */
799     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0, 
800         SWP_ASYNCWINDOWPOS|
801         SWP_FRAMECHANGED|
802         SWP_SHOWWINDOW|
803         SWP_NOMOVE|
804         SWP_NOSIZE|
805         SWP_NOZORDER );
806
807     /* use and restores proper display function for further pictures */
808     p_vout->pf_display = DisplayGAPI;
809 }
810
811 #endif
812
813 #undef rect_src
814 #undef rect_src_clipped
815 #undef rect_dest
816 #undef rect_dest_clipped
817 /*****************************************************************************
818  * SetPalette: sets an 8 bpp palette
819  *****************************************************************************/
820 static void SetPalette( vout_thread_t *p_vout,
821                         uint16_t *red, uint16_t *green, uint16_t *blue )
822 {
823     msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
824 }
825
826 /*****************************************************************************
827  * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
828  *****************************************************************************/
829 static void InitBuffers( vout_thread_t *p_vout )
830 {
831     BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
832     BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
833     int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
834     HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
835
836     /* Get screen properties */
837 #ifdef MODULE_NAME_IS_wingapi
838     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
839     p_vout->p_sys->i_depth = gx_displayprop.cBPP;
840 #else
841     p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
842         GetDeviceCaps( window_dc, BITSPIXEL );
843 #endif
844     msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
845
846 #ifdef MODULE_NAME_IS_wingapi
847     GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
848
849 #else
850
851     /* Initialize offscreen bitmap */
852     memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
853
854     p_header->biSize = sizeof( BITMAPINFOHEADER );
855     p_header->biSizeImage = 0;
856     p_header->biPlanes = 1;
857     switch( p_vout->p_sys->i_depth )
858     {
859     case 8:
860         p_header->biBitCount = 8;
861         p_header->biCompression = BI_RGB;
862         /* FIXME: we need a palette here */
863         break;
864     case 15:
865         p_header->biBitCount = 15;
866         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
867         ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
868         ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
869         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
870         break;
871     case 16:
872         p_header->biBitCount = 16;
873         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
874         ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
875         ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
876         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
877         break;
878     case 24:
879         p_header->biBitCount = 24;
880         p_header->biCompression = BI_RGB;
881         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
882         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
883         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
884         break;
885     case 32:
886         p_header->biBitCount = 32;
887         p_header->biCompression = BI_RGB;
888         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
889         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
890         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
891         break;
892     default:
893         msg_Err( p_vout, "screen depth %i not supported",
894                  p_vout->p_sys->i_depth );
895         return;
896         break;
897     }
898     p_header->biWidth = p_vout->render.i_width;
899     p_header->biHeight = -p_vout->render.i_height;
900     p_header->biClrImportant = 0;
901     p_header->biClrUsed = 0;
902     p_header->biXPelsPerMeter = 0;
903     p_header->biYPelsPerMeter = 0;
904
905     p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
906     p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
907
908     p_vout->p_sys->off_bitmap =
909         CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
910                           (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
911
912     p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
913
914     SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
915     ReleaseDC( p_vout->p_sys->hvideownd, window_dc );
916 #endif
917 }
918