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