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