]> git.sesse.net Git - vlc/blob - modules/video_output/msw/wingdi.c
Fixed invalid mouse cursor state on win32 (close #3675).
[vlc] / modules / video_output / msw / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 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 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_playlist.h>
37 #include <vlc_vout_display.h>
38
39 #include <windows.h>
40 #include <commctrl.h>
41
42 #include "common.h"
43
44 #ifndef WS_NONAVDONEBUTTON
45 #   define WS_NONAVDONEBUTTON 0
46 #endif
47
48 /*****************************************************************************
49  * Module descriptor
50  *****************************************************************************/
51 static int  Open (vlc_object_t *);
52 static void Close(vlc_object_t *);
53
54 vlc_module_begin ()
55     set_category(CAT_VIDEO)
56     set_subcategory(SUBCAT_VIDEO_VOUT)
57 #ifdef MODULE_NAME_IS_wingapi
58     set_shortname("GAPI")
59     set_description(N_("Windows GAPI video output"))
60     set_capability("vout display", 20)
61 #else
62     set_shortname("GDI")
63     set_description(N_("Windows GDI video output"))
64     set_capability("vout display", 10)
65 #endif
66     set_callbacks(Open, Close)
67 vlc_module_end ()
68
69
70 /*****************************************************************************
71  * Local prototypes
72  *****************************************************************************/
73 static picture_pool_t *Pool  (vout_display_t *, unsigned);
74 static void           Display(vout_display_t *, picture_t *);
75 static int            Control(vout_display_t *, int, va_list);
76 static void           Manage (vout_display_t *);
77
78 static int            Init(vout_display_t *, video_format_t *, int, int);
79 static void           Clean(vout_display_t *);
80
81 /* */
82 static int Open(vlc_object_t *object)
83 {
84     vout_display_t *vd = (vout_display_t *)object;
85     vout_display_sys_t *sys;
86
87     vd->sys = sys = calloc(1, sizeof(*sys));
88     if (!sys)
89         return VLC_ENOMEM;
90
91 #ifdef MODULE_NAME_IS_wingapi
92     /* Load GAPI */
93     sys->gapi_dll = LoadLibrary(_T("GX.DLL"));
94     if (!sys->gapi_dll) {
95         msg_Warn(vd, "failed loading gx.dll");
96         free(sys);
97         return VLC_EGENERIC;
98     }
99
100     GXOpenDisplay = (void *)GetProcAddress(sys->gapi_dll,
101         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z"));
102     GXCloseDisplay = (void *)GetProcAddress(sys->gapi_dll,
103         _T("?GXCloseDisplay@@YAHXZ"));
104     GXBeginDraw = (void *)GetProcAddress(sys->gapi_dll,
105         _T("?GXBeginDraw@@YAPAXXZ"));
106     GXEndDraw = (void *)GetProcAddress(sys->gapi_dll,
107         _T("?GXEndDraw@@YAHXZ"));
108     GXGetDisplayProperties = (void *)GetProcAddress(sys->gapi_dll,
109         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ"));
110     GXSuspend = (void *)GetProcAddress(sys->gapi_dll,
111         _T("?GXSuspend@@YAHXZ"));
112     GXResume = GetProcAddress(sys->gapi_dll,
113         _T("?GXResume@@YAHXZ"));
114
115     if (!GXOpenDisplay || !GXCloseDisplay ||
116         !GXBeginDraw || !GXEndDraw ||
117         !GXGetDisplayProperties || !GXSuspend || !GXResume) {
118         msg_Err(vd, "failed GetProcAddress on gapi.dll");
119         free(sys);
120         return VLC_EGENERIC;
121     }
122
123     msg_Dbg(vd, "GAPI DLL loaded");
124 #endif
125
126     if (CommonInit(vd))
127         goto error;
128
129     /* */
130     video_format_t fmt = vd->fmt;
131     if (Init(vd, &fmt, fmt.i_width, fmt.i_height))
132         goto error;
133
134     vout_display_info_t info = vd->info;
135     info.is_slow              = false;
136     info.has_double_click     = true;
137     info.has_hide_mouse       = false;
138     info.has_pictures_invalid = true;
139
140     /* */
141     vd->fmt  = fmt;
142     vd->info = info;
143
144     vd->pool    = Pool;
145     vd->prepare = NULL;
146     vd->display = Display;
147     vd->manage  = Manage;
148     vd->control = Control;
149     return VLC_SUCCESS;
150
151 error:
152     Close(VLC_OBJECT(vd));
153     return VLC_EGENERIC;
154 }
155
156 /* */
157 static void Close(vlc_object_t *object)
158 {
159     vout_display_t *vd = (vout_display_t *)object;
160
161     Clean(vd);
162
163     CommonClean(vd);
164
165 #ifdef MODULE_NAME_IS_wingapi
166     FreeLibrary(vd->sys->gapi_dll);
167 #endif
168
169     free(vd->sys);
170 }
171
172 /* */
173 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
174 {
175     VLC_UNUSED(count);
176     return vd->sys->pool;
177 }
178 static void Display(vout_display_t *vd, picture_t *picture)
179 {
180     vout_display_sys_t *sys = vd->sys;
181
182 #ifdef MODULE_NAME_IS_wingapi
183     /* */
184 #else
185 #define rect_src vd->sys->rect_src
186 #define rect_src_clipped vd->sys->rect_src_clipped
187 #define rect_dest vd->sys->rect_dest
188 #define rect_dest_clipped vd->sys->rect_dest_clipped
189     RECT rect_dst = rect_dest_clipped;
190     HDC hdc = GetDC(sys->hvideownd);
191
192     OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top);
193     SelectObject(sys->off_dc, sys->off_bitmap);
194
195     if (rect_dest_clipped.right - rect_dest_clipped.left !=
196         rect_src_clipped.right - rect_src_clipped.left ||
197         rect_dest_clipped.bottom - rect_dest_clipped.top !=
198         rect_src_clipped.bottom - rect_src_clipped.top) {
199         StretchBlt(hdc, rect_dst.left, rect_dst.top,
200                    rect_dst.right, rect_dst.bottom,
201                    sys->off_dc,
202                    rect_src_clipped.left,  rect_src_clipped.top,
203                    rect_src_clipped.right, rect_src_clipped.bottom,
204                    SRCCOPY);
205     } else {
206         BitBlt(hdc, rect_dst.left, rect_dst.top,
207                rect_dst.right, rect_dst.bottom,
208                sys->off_dc,
209                rect_src_clipped.left, rect_src_clipped.top,
210                SRCCOPY);
211     }
212
213     ReleaseDC(sys->hvideownd, hdc);
214 #undef rect_src
215 #undef rect_src_clipped
216 #undef rect_dest
217 #undef rect_dest_clipped
218 #endif
219     /* TODO */
220     picture_Release(picture);
221
222     CommonDisplay(vd);
223 }
224 static int Control(vout_display_t *vd, int query, va_list args)
225 {
226     switch (query) {
227     case VOUT_DISPLAY_RESET_PICTURES:
228         assert(0);
229         return VLC_EGENERIC;
230     default:
231         return CommonControl(vd, query, args);
232     }
233
234 }
235 static void Manage(vout_display_t *vd)
236 {
237     CommonManage(vd);
238 }
239
240 #ifdef MODULE_NAME_IS_wingapi
241 struct picture_sys_t {
242     vout_display_t *vd;
243 };
244
245 static int Lock(picture_t *picture)
246 {
247     vout_display_t *vd = picture->p_sys->vd;
248     vout_display_sys_t *sys = vd->sys;
249
250     /* */
251     if (sys->rect_dest_clipped.right  - sys->rect_dest_clipped.left != vd->fmt.i_width ||
252         sys->rect_dest_clipped.bottom - sys->rect_dest_clipped.top  != vd->fmt.i_height)
253         return VLC_EGENERIC;
254
255     /* */
256     GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
257     uint8_t *p_pic_buffer = GXBeginDraw();
258     if (!p_pic_buffer) {
259         msg_Err(vd, "GXBeginDraw error %d ", GetLastError());
260         return VLC_EGENERIC;
261     }
262     p_pic_buffer += sys->rect_dest.top  * gxdisplayprop.cbyPitch +
263                     sys->rect_dest.left * gxdisplayprop.cbxPitch;
264
265     /* */
266     picture->p[0].i_pitch  = gxdisplayprop.cbyPitch;
267     picture->p[0].p_pixels = p_pic_buffer;
268
269     return VLC_SUCCESS;
270 }
271 static void Unlock(picture_t *picture)
272 {
273     vout_display_t *vd = picture->p_sys->vd;
274
275     GXEndDraw();
276 }
277 #endif
278
279 static int Init(vout_display_t *vd,
280                 video_format_t *fmt, int width, int height)
281 {
282     vout_display_sys_t *sys = vd->sys;
283
284     /* */
285     RECT *display = &sys->rect_display;
286     display->left   = 0;
287     display->top    = 0;
288 #ifdef MODULE_NAME_IS_wingapi
289     display->right  = GXGetDisplayProperties().cxWidth;
290     display->bottom = GXGetDisplayProperties().cyHeight;
291 #else
292     display->right  = GetSystemMetrics(SM_CXSCREEN);;
293     display->bottom = GetSystemMetrics(SM_CYSCREEN);;
294 #endif
295
296     /* Initialize an offscreen bitmap for direct buffer operations. */
297
298     /* */
299     HDC window_dc = GetDC(sys->hvideownd);
300
301     /* */
302 #ifdef MODULE_NAME_IS_wingapi
303     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
304     sys->i_depth = gx_displayprop.cBPP;
305 #else
306
307     sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
308                    GetDeviceCaps(window_dc, BITSPIXEL);
309 #endif
310
311     /* */
312     msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
313     switch (sys->i_depth) {
314     case 8:
315         fmt->i_chroma = VLC_CODEC_RGB8;
316         break;
317     case 15:
318         fmt->i_chroma = VLC_CODEC_RGB15;
319         fmt->i_rmask  = 0x7c00;
320         fmt->i_gmask  = 0x03e0;
321         fmt->i_bmask  = 0x001f;
322         break;
323     case 16:
324         fmt->i_chroma = VLC_CODEC_RGB16;
325         fmt->i_rmask  = 0xf800;
326         fmt->i_gmask  = 0x07e0;
327         fmt->i_bmask  = 0x001f;
328         break;
329     case 24:
330         fmt->i_chroma = VLC_CODEC_RGB24;
331         fmt->i_rmask  = 0x00ff0000;
332         fmt->i_gmask  = 0x0000ff00;
333         fmt->i_bmask  = 0x000000ff;
334         break;
335     case 32:
336         fmt->i_chroma = VLC_CODEC_RGB32;
337         fmt->i_rmask  = 0x00ff0000;
338         fmt->i_gmask  = 0x0000ff00;
339         fmt->i_bmask  = 0x000000ff;
340         break;
341     default:
342         msg_Err(vd, "screen depth %i not supported", sys->i_depth);
343         return VLC_EGENERIC;
344     }
345     fmt->i_width  = width;
346     fmt->i_height = height;
347
348     uint8_t *p_pic_buffer;
349     int     i_pic_pitch;
350 #ifdef MODULE_NAME_IS_wingapi
351     GXOpenDisplay(sys->hvideownd, GX_FULLSCREEN);
352     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGAPI output)");
353
354     /* Filled by pool::lock() */
355     p_pic_buffer = NULL;
356     i_pic_pitch  = 0;
357 #else
358     /* Initialize offscreen bitmap */
359     BITMAPINFO *bi = &sys->bitmapinfo;
360     memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
361     if (sys->i_depth > 8) {
362         ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
363         ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
364         ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
365     }
366
367     BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
368     bih->biSize = sizeof(BITMAPINFOHEADER);
369     bih->biSizeImage     = 0;
370     bih->biPlanes        = 1;
371     bih->biCompression   = (sys->i_depth == 15 ||
372                             sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
373     bih->biBitCount      = sys->i_depth;
374     bih->biWidth         = fmt->i_width;
375     bih->biHeight        = -fmt->i_height;
376     bih->biClrImportant  = 0;
377     bih->biClrUsed       = 0;
378     bih->biXPelsPerMeter = 0;
379     bih->biYPelsPerMeter = 0;
380
381     i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
382     sys->off_bitmap = CreateDIBSection(window_dc,
383                                        (BITMAPINFO *)bih,
384                                        DIB_RGB_COLORS,
385                                        &p_pic_buffer, NULL, 0);
386
387     sys->off_dc = CreateCompatibleDC(window_dc);
388
389     SelectObject(sys->off_dc, sys->off_bitmap);
390     ReleaseDC(sys->hvideownd, window_dc);
391
392     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGDI output)");
393 #endif
394
395     /* */
396     picture_resource_t rsc;
397     memset(&rsc, 0, sizeof(rsc));
398 #ifdef MODULE_NAME_IS_wingapi
399     rsc.p_sys = malloc(sizeof(*rsc.p_sys));
400     if (!rsc.p_sys)
401         return VLC_EGENERIC;
402     rsc.p_sys->vd = vd;
403 #endif
404     rsc.p[0].p_pixels = p_pic_buffer;
405     rsc.p[0].i_lines  = fmt->i_height;
406     rsc.p[0].i_pitch  = i_pic_pitch;;
407
408     picture_t *picture = picture_NewFromResource(fmt, &rsc);
409     if (picture) {
410         picture_pool_configuration_t cfg;
411         memset(&cfg, 0, sizeof(cfg));
412         cfg.picture_count = 1;
413         cfg.picture = &picture;
414 #ifdef MODULE_NAME_IS_wingapi
415         cfg.lock    = Lock;
416         cfg.unlock  = Unlock;
417 #endif
418         sys->pool = picture_pool_NewExtended(&cfg);
419     } else {
420         free(rsc.p_sys);
421         sys->pool = NULL;
422     }
423
424     UpdateRects(vd, NULL, NULL, true);
425
426     return VLC_SUCCESS;
427 }
428
429 static void Clean(vout_display_t *vd)
430 {
431     vout_display_sys_t *sys = vd->sys;
432
433     if (sys->pool)
434         picture_pool_Delete(sys->pool);
435     sys->pool = NULL;
436
437 #ifdef MODULE_NAME_IS_wingapi
438     GXCloseDisplay();
439 #else
440     if (sys->off_dc)
441         DeleteDC(sys->off_dc);
442     if (sys->off_bitmap)
443         DeleteObject(sys->off_bitmap);
444 #endif
445 }
446