freetype: font fallback for Windows
[vlc.git] / modules / video_output / kva.c
blobeb9aed4a991d15b277f07b1c8a426fde8299ee69
1 /*****************************************************************************
2 * kva.c: KVA video output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010, 2011, 2012 VLC authors and VideoLAN
6 * Authors: KO Myung-Hun <komh@chollian.net>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_vout_display.h>
33 #include <vlc_picture_pool.h>
35 #include <ctype.h>
36 #include <float.h>
37 #include <assert.h>
39 #include <fourcc.h>
41 #include <kva.h>
43 /*****************************************************************************
44 * Module descriptor
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
49 #define KVA_FIXT23_TEXT N_( \
50 "Enable a workaround for T23" )
51 #define KVA_FIXT23_LONGTEXT N_( \
52 "Enable this option if the diagonal stripes are displayed " \
53 "when the window size is equal to or smaller than the movie size." )
54 #define KVA_VIDEO_MODE_TEXT N_( \
55 "Video mode" )
56 #define KVA_VIDEO_MODE_LONGTEXT N_( \
57 "Select a proper video mode to be used by KVA." )
59 static const char *const ppsz_kva_video_mode[] = {
60 "auto", "snap", "wo", "vman", "dive" };
61 static const char *const ppsz_kva_video_mode_text[] = {
62 N_("Auto"), N_("SNAP"), N_("WarpOverlay!"), N_("VMAN"), N_("DIVE") };
64 vlc_module_begin ()
65 set_shortname( "KVA" )
66 set_category( CAT_VIDEO )
67 set_subcategory( SUBCAT_VIDEO_VOUT )
68 add_string( "kva-video-mode", ppsz_kva_video_mode[0], KVA_VIDEO_MODE_TEXT,
69 KVA_VIDEO_MODE_LONGTEXT, false )
70 change_string_list( ppsz_kva_video_mode, ppsz_kva_video_mode_text )
71 add_bool( "kva-fixt23", false, KVA_FIXT23_TEXT, KVA_FIXT23_LONGTEXT, true )
72 set_description( N_("K Video Acceleration video output") )
73 set_capability( "vout display", 100 )
74 add_shortcut( "kva" )
75 set_callbacks( Open, Close )
76 vlc_module_end ()
78 /*****************************************************************************
79 * vout_display_sys_t: video output method descriptor
80 *****************************************************************************
81 * This structure is part of the video output thread descriptor.
82 * It describes the module specific properties of an output thread.
83 *****************************************************************************/
84 struct vout_display_sys_t
86 TID tid;
87 HEV ack_event;
88 int i_result;
89 HAB hab;
90 HMQ hmq;
91 HWND frame;
92 HWND client;
93 KVASETUP kvas;
94 KVACAPS kvac;
95 LONG i_screen_width;
96 LONG i_screen_height;
97 bool b_fixt23;
98 PFNWP p_old_frame;
99 RECTL client_rect;
100 vout_window_t *parent_window;
101 HWND parent;
102 RECTL parent_rect;
103 picture_pool_t *pool;
104 unsigned button_pressed;
105 bool is_mouse_hidden;
106 bool is_on_top;
109 struct picture_sys_t
111 int i_chroma_shift;
114 /*****************************************************************************
115 * Local prototypes
116 *****************************************************************************/
117 static picture_pool_t *Pool (vout_display_t *, unsigned);
118 static void Display(vout_display_t *, picture_t *, subpicture_t * );
119 static int Control(vout_display_t *, int, va_list);
120 static void Manage (vout_display_t *);
122 static int OpenDisplay ( vout_display_t *, video_format_t * );
123 static void CloseDisplay( vout_display_t * );
125 static int KVALock( picture_t * );
126 static void KVAUnlock( picture_t * );
128 static void MorphToPM ( void );
129 static int ConvertKey ( USHORT );
130 static MRESULT EXPENTRY MyFrameWndProc( HWND, ULONG, MPARAM, MPARAM );
131 static MRESULT EXPENTRY WndProc ( HWND, ULONG, MPARAM, MPARAM );
133 #define WC_VLC_KVA "WC_VLC_KVA"
135 #define COLOR_KEY 0x0F0F0F
137 #define WM_VLC_MANAGE ( WM_USER + 1 )
138 #define WM_VLC_FULLSCREEN_CHANGE ( WM_USER + 2 )
139 #define WM_VLC_SIZE_CHANGE ( WM_USER + 3 )
141 static const char *psz_video_mode[ 4 ] = {"DIVE", "WarpOverlay!", "SNAP",
142 "VMAN"};
144 static void PMThread( void *arg )
146 vout_display_t *vd = ( vout_display_t * )arg;
147 vout_display_sys_t * sys = vd->sys;
148 ULONG i_frame_flags;
149 QMSG qm;
150 char *psz_mode;
151 ULONG i_kva_mode;
153 /* */
154 video_format_t fmt;
155 video_format_ApplyRotation(&fmt, &vd->fmt);
157 /* */
158 vout_display_info_t info = vd->info;
159 info.is_slow = false;
160 info.has_double_click = true;
161 info.has_hide_mouse = false;
162 info.has_pictures_invalid = false;
164 MorphToPM();
166 sys->hab = WinInitialize( 0 );
167 sys->hmq = WinCreateMsgQueue( sys->hab, 0);
169 WinRegisterClass( sys->hab,
170 WC_VLC_KVA,
171 WndProc,
172 CS_SIZEREDRAW | CS_MOVENOTIFY,
173 sizeof( PVOID ));
175 sys->b_fixt23 = var_CreateGetBool( vd, "kva-fixt23");
177 if( !sys->b_fixt23 )
178 /* If an external window was specified, we'll draw in it. */
179 sys->parent_window =
180 vout_display_NewWindow( vd, VOUT_WINDOW_TYPE_HWND );
182 if( sys->parent_window )
184 sys->parent = ( HWND )sys->parent_window->handle.hwnd;
186 ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE );
187 WinSetWindowULong( sys->parent, QWL_STYLE,
188 i_style | WS_CLIPCHILDREN );
190 i_frame_flags = FCF_TITLEBAR;
192 else
194 sys->parent = HWND_DESKTOP;
196 i_frame_flags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX |
197 FCF_SIZEBORDER | FCF_TASKLIST;
200 sys->frame =
201 WinCreateStdWindow( sys->parent, /* parent window handle */
202 WS_VISIBLE, /* frame window style */
203 &i_frame_flags, /* window style */
204 WC_VLC_KVA, /* class name */
205 "", /* window title */
206 0L, /* default client style */
207 NULLHANDLE, /* resource in exe file */
208 1, /* frame window id */
209 &sys->client ); /* client window handle */
211 if( sys->frame == NULLHANDLE )
213 msg_Err( vd, "cannot create a frame window");
215 goto exit_frame;
218 WinSetWindowPtr( sys->client, 0, vd );
220 if( !sys->parent_window )
222 WinSetWindowPtr( sys->frame, 0, vd );
223 sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc );
226 psz_mode = var_CreateGetString( vd, "kva-video-mode" );
228 i_kva_mode = KVAM_AUTO;
229 if( strcmp( psz_mode, "snap" ) == 0 )
230 i_kva_mode = KVAM_SNAP;
231 else if( strcmp( psz_mode, "wo" ) == 0 )
232 i_kva_mode = KVAM_WO;
233 else if( strcmp( psz_mode, "vman" ) == 0 )
234 i_kva_mode = KVAM_VMAN;
235 else if( strcmp( psz_mode, "dive" ) == 0 )
236 i_kva_mode = KVAM_DIVE;
238 free( psz_mode );
240 if( kvaInit( i_kva_mode, sys->client, COLOR_KEY ))
242 msg_Err( vd, "cannot initialize KVA");
244 goto exit_kva_init;
247 kvaCaps( &sys->kvac );
249 msg_Dbg( vd, "selected video mode = %s",
250 psz_video_mode[ sys->kvac.ulMode - 1 ]);
252 if( OpenDisplay( vd, &fmt ) )
254 msg_Err( vd, "cannot open display");
256 goto exit_open_display;
259 if( vd->cfg->is_fullscreen && !sys->parent_window )
260 WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE,
261 MPFROMLONG( true ), 0 );
263 kvaDisableScreenSaver();
265 /* Setup vout_display now that everything is fine */
266 vd->fmt = fmt;
267 vd->info = info;
269 vd->pool = Pool;
270 vd->prepare = NULL;
271 vd->display = Display;
272 vd->control = Control;
273 vd->manage = Manage;
275 /* Prevent SIG_FPE */
276 _control87(MCW_EM, MCW_EM);
278 sys->i_result = VLC_SUCCESS;
279 DosPostEventSem( sys->ack_event );
281 if( !sys->parent_window )
282 WinSetVisibleRegionNotify( sys->frame, TRUE );
284 while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 ))
285 WinDispatchMsg( sys->hab, &qm );
287 if( !sys->parent_window )
288 WinSetVisibleRegionNotify( sys->frame, FALSE );
290 kvaEnableScreenSaver();
292 CloseDisplay( vd );
294 /* fall through */
296 exit_open_display :
297 kvaDone();
299 exit_kva_init :
300 if( !sys->parent_window )
301 WinSubclassWindow( sys->frame, sys->p_old_frame );
303 WinDestroyWindow( sys->frame );
305 exit_frame :
306 vout_display_DeleteWindow( vd, sys->parent_window );
308 if( sys->is_mouse_hidden )
309 WinShowPointer( HWND_DESKTOP, TRUE );
311 WinDestroyMsgQueue( sys->hmq );
312 WinTerminate( sys->hab );
314 sys->i_result = VLC_EGENERIC;
315 DosPostEventSem( sys->ack_event );
319 * This function initializes KVA vout method.
321 static int Open ( vlc_object_t *object )
323 vout_display_t *vd = (vout_display_t *)object;
324 vout_display_sys_t *sys;
326 vd->sys = sys = calloc( 1, sizeof( *sys ));
327 if( !sys )
328 return VLC_ENOMEM;
330 DosCreateEventSem( NULL, &sys->ack_event, 0, FALSE );
332 sys->tid = _beginthread( PMThread, NULL, 1024 * 1024, vd );
333 DosWaitEventSem( sys->ack_event, SEM_INDEFINITE_WAIT );
335 if( sys->i_result != VLC_SUCCESS )
337 DosCloseEventSem( sys->ack_event );
339 free( sys );
341 return VLC_EGENERIC;
344 return VLC_SUCCESS;
347 /*****************************************************************************
348 * Close: destroy KVA video thread output method
349 *****************************************************************************
350 * Terminate an output method created by Open
351 *****************************************************************************/
352 static void Close ( vlc_object_t *object )
354 vout_display_t * vd = (vout_display_t *)object;
355 vout_display_sys_t * sys = vd->sys;
357 WinPostQueueMsg( sys->hmq, WM_QUIT, 0, 0 );
359 DosWaitThread( &sys->tid, DCWW_WAIT );
361 if( sys->pool )
362 picture_pool_Release( sys->pool );
364 DosCloseEventSem( sys->ack_event );
366 free( sys );
370 * Return a pool of direct buffers
372 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
374 vout_display_sys_t *sys = vd->sys;
375 VLC_UNUSED(count);
377 return sys->pool;
380 /*****************************************************************************
381 * Display: displays previously rendered output
382 *****************************************************************************
383 * This function sends the currently rendered image to the display.
384 *****************************************************************************/
385 static void Display( vout_display_t *vd, picture_t *picture,
386 subpicture_t *subpicture )
388 VLC_UNUSED( vd );
389 VLC_UNUSED( subpicture );
391 picture_Release( picture );
394 /*****************************************************************************
395 * Manage: handle Sys events
396 *****************************************************************************
397 * This function should be called regularly by video output thread. It returns
398 * a non null value if an error occurred.
399 *****************************************************************************/
400 static void Manage( vout_display_t *vd )
402 vout_display_sys_t * sys = vd->sys;
404 /* Let a window procedure manage instead because if resizing a frame window
405 * here, WM_SIZE is not sent to its child window.
406 * Maybe, is this due to the different threads ? */
407 WinPostMsg( sys->client, WM_VLC_MANAGE, 0, 0 );
410 /*****************************************************************************
411 * Control: control facility for the vout
412 *****************************************************************************/
413 static int Control( vout_display_t *vd, int query, va_list args )
415 vout_display_sys_t *sys = vd->sys;
417 switch (query)
419 case VOUT_DISPLAY_HIDE_MOUSE:
421 POINTL ptl;
423 WinQueryPointerPos( HWND_DESKTOP, &ptl );
424 if( !sys->is_mouse_hidden &&
425 WinWindowFromPoint( HWND_DESKTOP, &ptl, TRUE ) == sys->client )
427 WinShowPointer( HWND_DESKTOP, FALSE );
428 sys->is_mouse_hidden = true;
431 return VLC_SUCCESS;
434 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
436 bool fs = va_arg(args, int);
438 WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, MPFROMLONG(fs), 0 );
439 return VLC_SUCCESS;
442 case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
444 const unsigned state = va_arg( args, unsigned );
445 const bool is_on_top = (state & VOUT_WINDOW_STATE_ABOVE) != 0;
447 if( is_on_top )
448 WinSetWindowPos( sys->frame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
450 sys->is_on_top = is_on_top;
452 return VLC_SUCCESS;
455 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
456 case VOUT_DISPLAY_CHANGE_ZOOM:
458 const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
460 WinPostMsg( sys->client, WM_VLC_SIZE_CHANGE,
461 MPFROMLONG( cfg->display.width ),
462 MPFROMLONG( cfg->display.height ));
463 return VLC_SUCCESS;
466 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
467 case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
469 const video_format_t *src = va_arg(args, const video_format_t *);
471 if( query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT )
473 vout_display_place_t place;
474 vout_display_PlacePicture(&place, src, vd->cfg, false);
476 sys->kvas.ulAspectWidth = place.width;
477 sys->kvas.ulAspectHeight = place.height;
479 else
481 video_format_t src_rot;
482 video_format_ApplyRotation(&src_rot, src);
484 sys->kvas.rclSrcRect.xLeft = src_rot.i_x_offset;
485 sys->kvas.rclSrcRect.yTop = src_rot.i_y_offset;
486 sys->kvas.rclSrcRect.xRight = src_rot.i_x_offset +
487 src_rot.i_visible_width;
488 sys->kvas.rclSrcRect.yBottom = src_rot.i_y_offset +
489 src_rot.i_visible_height;
492 kvaSetup( &sys->kvas );
494 return VLC_SUCCESS;
497 case VOUT_DISPLAY_RESET_PICTURES:
498 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
499 /* TODO */
500 break;
503 msg_Err(vd, "Unsupported query(=%d) in vout display KVA", query);
504 return VLC_EGENERIC;
507 /* following functions are local */
509 /*****************************************************************************
510 * OpenDisplay: open and initialize KVA device
511 *****************************************************************************
512 * Open and initialize display according to preferences specified in the vout
513 * thread fields.
514 *****************************************************************************/
515 static int OpenDisplay( vout_display_t *vd, video_format_t *fmt )
517 vout_display_sys_t * sys = vd->sys;
518 const vlc_fourcc_t *fallback;
519 bool b_hw_accel = 0;
520 FOURCC i_kva_fourcc;
521 int i_chroma_shift;
522 char sz_title[ 256 ];
523 RECTL rcl;
524 int w, h;
526 msg_Dbg( vd, "render chroma = %4.4s", ( const char * )&fmt->i_chroma );
528 for( int pass = 0; pass < 2 && !b_hw_accel; pass++ )
530 fallback = ( pass == 0 ) ? vlc_fourcc_GetYUVFallback( fmt->i_chroma ) :
531 vlc_fourcc_GetRGBFallback( fmt->i_chroma );
533 for( int i = 0; fallback[ i ]; i++ )
535 switch( fallback[ i ])
537 case VLC_CODEC_YV12:
538 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12;
539 i_kva_fourcc = FOURCC_YV12;
540 i_chroma_shift = 1;
541 break;
543 case VLC_CODEC_YUYV:
544 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YUY2;
545 i_kva_fourcc = FOURCC_Y422;
546 i_chroma_shift = 0;
547 break;
549 case VLC_CODEC_YV9:
550 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YVU9;
551 i_kva_fourcc = FOURCC_YVU9;
552 i_chroma_shift = 2;
553 break;
555 case VLC_CODEC_RGB32:
556 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR32;
557 i_kva_fourcc = FOURCC_BGR4;
558 i_chroma_shift = 0;
559 break;
561 case VLC_CODEC_RGB24:
562 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR24;
563 i_kva_fourcc = FOURCC_BGR3;
564 i_chroma_shift = 0;
565 break;
567 case VLC_CODEC_RGB16:
568 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR16;
569 i_kva_fourcc = FOURCC_R565;
570 i_chroma_shift = 0;
571 break;
573 case VLC_CODEC_RGB15:
574 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR15;
575 i_kva_fourcc = FOURCC_R555;
576 i_chroma_shift = 0;
577 break;
580 if( b_hw_accel )
582 fmt->i_chroma = fallback[ i ];
583 break;
588 if( !b_hw_accel )
590 msg_Err( vd, "Ooops. There is no fourcc supported by KVA at all.");
592 return VLC_EGENERIC;
595 /* Set the RGB masks */
596 fmt->i_rmask = sys->kvac.ulRMask;
597 fmt->i_gmask = sys->kvac.ulGMask;
598 fmt->i_bmask = sys->kvac.ulBMask;
600 msg_Dbg( vd, "output chroma = %4.4s", ( const char * )&fmt->i_chroma );
601 msg_Dbg( vd, "KVA chroma = %4.4s", ( const char * )&i_kva_fourcc );
603 w = fmt->i_width;
604 h = fmt->i_height;
606 sys->kvas.ulLength = sizeof( KVASETUP );
607 sys->kvas.szlSrcSize.cx = w;
608 sys->kvas.szlSrcSize.cy = h;
609 sys->kvas.rclSrcRect.xLeft = fmt->i_x_offset;
610 sys->kvas.rclSrcRect.yTop = fmt->i_y_offset;
611 sys->kvas.rclSrcRect.xRight = fmt->i_x_offset + fmt->i_visible_width;
612 sys->kvas.rclSrcRect.yBottom = fmt->i_y_offset + fmt->i_visible_height;
613 sys->kvas.ulRatio = KVAR_FORCEANY;
614 sys->kvas.ulAspectWidth = w;
615 sys->kvas.ulAspectHeight = h;
616 sys->kvas.fccSrcColor = i_kva_fourcc;
617 sys->kvas.fDither = TRUE;
619 if( kvaSetup( &sys->kvas ))
621 msg_Err( vd, "cannot set up KVA");
623 return VLC_EGENERIC;
626 /* Create the associated picture */
627 picture_sys_t *picsys = malloc( sizeof( *picsys ) );
628 if( picsys == NULL )
629 return VLC_ENOMEM;
630 picsys->i_chroma_shift = i_chroma_shift;
632 picture_resource_t resource = { .p_sys = picsys };
633 picture_t *picture = picture_NewFromResource( fmt, &resource );
634 if( !picture )
636 free( picsys );
637 return VLC_ENOMEM;
640 /* Wrap it into a picture pool */
641 picture_pool_configuration_t pool_cfg;
642 memset( &pool_cfg, 0, sizeof( pool_cfg ));
643 pool_cfg.picture_count = 1;
644 pool_cfg.picture = &picture;
645 pool_cfg.lock = KVALock;
646 pool_cfg.unlock = KVAUnlock;
648 sys->pool = picture_pool_NewExtended( &pool_cfg );
649 if( !sys->pool )
651 picture_Release( picture );
652 return VLC_ENOMEM;
655 if (vd->cfg->display.title)
656 snprintf( sz_title, sizeof( sz_title ), "%s", vd->cfg->display.title );
657 else
658 snprintf( sz_title, sizeof( sz_title ),
659 "%s (%4.4s to %4.4s - %s mode KVA output)",
660 VOUT_TITLE,
661 ( char * )&vd->fmt.i_chroma,
662 ( char * )&sys->kvas.fccSrcColor,
663 psz_video_mode[ sys->kvac.ulMode - 1 ]);
664 WinSetWindowText( sys->frame, sz_title );
666 sys->i_screen_width = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
667 sys->i_screen_height = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
669 if( sys->parent_window )
670 WinQueryWindowRect( sys->parent, &sys->client_rect );
671 else
673 sys->client_rect.xLeft = ( sys->i_screen_width - w ) / 2;
674 sys->client_rect.yBottom = ( sys->i_screen_height - h ) / 2 ;
675 sys->client_rect.xRight = sys->client_rect.xLeft + w;
676 sys->client_rect.yTop = sys->client_rect.yBottom + h;
679 rcl = sys->client_rect;
681 WinCalcFrameRect( sys->frame, &rcl, FALSE);
683 WinSetWindowPos( sys->frame, HWND_TOP,
684 rcl.xLeft, rcl.yBottom,
685 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
686 SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
687 SWP_ACTIVATE );
689 return VLC_SUCCESS;
692 /*****************************************************************************
693 * CloseDisplay: close and reset KVA device
694 *****************************************************************************
695 * This function returns all resources allocated by OpenDisplay and restore
696 * the original state of the device.
697 *****************************************************************************/
698 static void CloseDisplay( vout_display_t *vd )
700 VLC_UNUSED( vd );
703 static int KVALock( picture_t *picture )
705 picture_sys_t *picsys = picture->p_sys;
706 PVOID kva_buffer;
707 ULONG kva_bpl;
709 if( kvaLockBuffer( &kva_buffer, &kva_bpl ))
710 return VLC_EGENERIC;
712 /* Packed or Y plane */
713 picture->p->p_pixels = ( uint8_t * )kva_buffer;
714 picture->p->i_pitch = kva_bpl;
715 picture->p->i_lines = picture->format.i_height;
717 /* Other planes */
718 for( int n = 1; n < picture->i_planes; n++ )
720 const plane_t *o = &picture->p[n-1];
721 plane_t *p = &picture->p[n];
723 p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
724 p->i_pitch = kva_bpl >> picsys->i_chroma_shift;
725 p->i_lines = picture->format.i_height >> picsys->i_chroma_shift;
728 return VLC_SUCCESS;
731 static void KVAUnlock( picture_t *picture )
733 VLC_UNUSED( picture );
735 kvaUnlockBuffer();
738 static void MorphToPM( void )
740 PPIB pib;
742 DosGetInfoBlocks(NULL, &pib);
744 /* Change flag from VIO to PM */
745 if (pib->pib_ultype == 2)
746 pib->pib_ultype = 3;
749 /*****************************************************************************
750 * Key events handling
751 *****************************************************************************/
752 static const struct
754 USHORT i_pmkey;
755 int i_vlckey;
756 } pmkeys_to_vlckeys[] =
758 { VK_LEFT, KEY_LEFT },
759 { VK_RIGHT, KEY_RIGHT },
760 { VK_UP, KEY_UP },
761 { VK_DOWN, KEY_DOWN },
762 { VK_SPACE, ' ' },
763 { VK_NEWLINE, KEY_ENTER },
764 { VK_ENTER, KEY_ENTER },
765 { VK_F1, KEY_F1 },
766 { VK_F2, KEY_F2 },
767 { VK_F3, KEY_F3 },
768 { VK_F4, KEY_F4 },
769 { VK_F5, KEY_F5 },
770 { VK_F6, KEY_F6 },
771 { VK_F7, KEY_F7 },
772 { VK_F8, KEY_F8 },
773 { VK_F9, KEY_F9 },
774 { VK_F10, KEY_F10 },
775 { VK_F11, KEY_F11 },
776 { VK_F12, KEY_F12 },
777 { VK_HOME, KEY_HOME },
778 { VK_END, KEY_END },
779 { VK_INSERT, KEY_INSERT },
780 { VK_DELETE, KEY_DELETE },
782 Not supported
783 {, KEY_MENU },
785 { VK_ESC, KEY_ESC },
786 { VK_PAGEUP, KEY_PAGEUP },
787 { VK_PAGEDOWN, KEY_PAGEDOWN },
788 { VK_TAB, KEY_TAB },
789 { VK_BACKSPACE, KEY_BACKSPACE },
791 Not supported
792 {, KEY_MOUSEWHEELUP },
793 {, KEY_MOUSEWHEELDOWN },
794 {, KEY_MOUSEWHEELLEFT },
795 {, KEY_MOUSEWHEELRIGHT },
797 {, KEY_BROWSER_BACK },
798 {, KEY_BROWSER_FORWARD },
799 {, KEY_BROWSER_REFRESH },
800 {, KEY_BROWSER_STOP },
801 {, KEY_BROWSER_SEARCH },
802 {, KEY_BROWSER_FAVORITES },
803 {, KEY_BROWSER_HOME },
804 {, KEY_VOLUME_MUTE },
805 {, KEY_VOLUME_DOWN },
806 {, KEY_VOLUME_UP },
807 {, KEY_MEDIA_NEXT_TRACK },
808 {, KEY_MEDIA_PREV_TRACK },
809 {, KEY_MEDIA_STOP },
810 {, KEY_MEDIA_PLAY_PAUSE },
813 { 0, 0 }
816 static int ConvertKey( USHORT i_pmkey )
818 int i;
819 for( i = 0; pmkeys_to_vlckeys[ i ].i_pmkey != 0; i++ )
821 if( pmkeys_to_vlckeys[ i ].i_pmkey == i_pmkey )
822 return pmkeys_to_vlckeys[ i ].i_vlckey;
824 return 0;
827 static MRESULT EXPENTRY MyFrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1,
828 MPARAM mp2 )
830 vout_display_t *vd = WinQueryWindowPtr( hwnd, 0 );
831 vout_display_sys_t *sys = vd->sys;
833 switch( msg )
835 case WM_QUERYTRACKINFO :
837 MRESULT mr;
839 mr = sys->p_old_frame( hwnd, msg, mp1, mp2 );
840 if( !sys->b_fixt23 )
841 return mr;
843 PTRACKINFO pti = ( PTRACKINFO )mp2;
844 RECTL rcl;
846 pti->rclBoundary.xLeft = 0;
847 pti->rclBoundary.yBottom = 0;
848 pti->rclBoundary.xRight = sys->i_screen_width;
849 pti->rclBoundary.yTop = sys->i_screen_height;
851 WinCalcFrameRect( hwnd, &pti->rclBoundary, FALSE );
853 pti->ptlMaxTrackSize.x = pti->rclBoundary.xRight -
854 pti->rclBoundary.xLeft;
855 pti->ptlMaxTrackSize.y = pti->rclBoundary.yTop -
856 pti->rclBoundary.yBottom;
858 rcl.xLeft = 0;
859 rcl.yBottom = 0;
860 rcl.xRight = sys->kvas.szlSrcSize.cx + 1;
861 rcl.yTop = sys->kvas.szlSrcSize.cy + 1;
863 WinCalcFrameRect( hwnd, &rcl, FALSE );
865 pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft;
866 pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom;
868 return MRFROMLONG( TRUE );
871 case WM_ADJUSTWINDOWPOS :
873 if( !sys->b_fixt23 )
874 break;
876 PSWP pswp = ( PSWP )mp1;
878 if( pswp->fl & SWP_SIZE )
880 RECTL rcl;
882 rcl.xLeft = pswp->x;
883 rcl.yBottom = pswp->y;
884 rcl.xRight = rcl.xLeft + pswp->cx;
885 rcl.yTop = rcl.yBottom + pswp->cy;
887 WinCalcFrameRect( hwnd, &rcl, TRUE );
889 if( rcl.xRight - rcl.xLeft <= sys->kvas.szlSrcSize.cx )
890 rcl.xRight = rcl.xLeft + ( sys->kvas.szlSrcSize.cx + 1 );
892 if( rcl.yTop - rcl.yBottom <= sys->kvas.szlSrcSize.cy )
893 rcl.yTop = rcl.yBottom + ( sys->kvas.szlSrcSize.cy + 1 );
895 if( rcl.xRight - rcl.xLeft > sys->i_screen_width )
897 rcl.xLeft = 0;
898 rcl.xRight = sys->i_screen_width;
901 if( rcl.yTop - rcl.yBottom > sys->i_screen_height )
903 rcl.yBottom = 0;
904 rcl.yTop = sys->i_screen_height;
907 WinCalcFrameRect( hwnd, &rcl, FALSE );
909 if( pswp->x != rcl.xLeft || pswp->y != rcl.yBottom )
910 pswp->fl |= SWP_MOVE;
912 pswp->x = rcl.xLeft;
913 pswp->y = rcl.yBottom;
915 pswp->cx = rcl.xRight - rcl.xLeft;
916 pswp->cy = rcl.yTop - rcl.yBottom;
919 break;
922 //case WM_VRNDISABLED :
923 case WM_VRNENABLED :
924 if( !vd->cfg->is_fullscreen && sys->is_on_top )
925 WinSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
926 break;
929 return sys->p_old_frame( hwnd, msg, mp1, mp2 );
932 static void MousePressed( vout_display_t *vd, HWND hwnd, unsigned button )
934 if( WinQueryFocus( HWND_DESKTOP ) != hwnd )
935 WinSetFocus( HWND_DESKTOP, hwnd );
937 if( !vd->sys->button_pressed )
938 WinSetCapture( HWND_DESKTOP, hwnd );
940 vd->sys->button_pressed |= 1 << button;
942 vout_display_SendEventMousePressed( vd, button );
945 static void MouseReleased( vout_display_t *vd, unsigned button )
947 vd->sys->button_pressed &= ~(1 << button);
948 if( !vd->sys->button_pressed )
949 WinSetCapture( HWND_DESKTOP, NULLHANDLE );
951 vout_display_SendEventMouseReleased( vd, button );
954 #define WM_MOUSELEAVE 0x41F
956 static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
958 vout_display_t * vd = WinQueryWindowPtr( hwnd, 0 );
959 MRESULT result = ( MRESULT )TRUE;
961 if ( !vd )
962 return WinDefWindowProc( hwnd, msg, mp1, mp2 );
964 vout_display_sys_t * sys = vd->sys;
965 RECTL rcl;
966 SWP swp;
968 if ( sys->is_mouse_hidden &&
969 ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
970 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST) ||
971 msg == WM_MOUSELEAVE))
973 WinShowPointer(HWND_DESKTOP, TRUE);
974 sys->is_mouse_hidden = false;
977 switch( msg )
979 /* the user wants to close the window */
980 case WM_CLOSE:
981 vout_display_SendEventClose(vd);
982 result = 0;
983 break;
985 case WM_MOUSEMOVE :
987 SHORT i_mouse_x = SHORT1FROMMP( mp1 );
988 SHORT i_mouse_y = SHORT2FROMMP( mp1 );
989 RECTL movie_rect;
990 int i_movie_width, i_movie_height;
991 int i_src_width, i_src_height;
993 /* Get a current movie area */
994 kvaAdjustDstRect( &sys->kvas.rclSrcRect, &movie_rect );
995 i_movie_width = movie_rect.xRight - movie_rect.xLeft;
996 i_movie_height = movie_rect.yTop - movie_rect.yBottom;
998 i_src_width = sys->kvas.rclSrcRect.xRight -
999 sys->kvas.rclSrcRect.xLeft;
1000 i_src_height = sys->kvas.rclSrcRect.yBottom -
1001 sys->kvas.rclSrcRect.yTop;
1003 int x = ( i_mouse_x - movie_rect.xLeft ) *
1004 i_src_width / i_movie_width +
1005 sys->kvas.rclSrcRect.xLeft;
1006 int y = ( i_mouse_y - movie_rect.yBottom ) *
1007 i_src_height / i_movie_height;
1009 /* Invert Y coordinate and add y offset */
1010 y = ( i_src_height - y ) + sys->kvas.rclSrcRect.yTop;;
1012 vout_display_SendEventMouseMoved(vd, x, y);
1014 result = WinDefWindowProc( hwnd, msg, mp1,mp2 );
1015 break;
1018 case WM_BUTTON1DOWN :
1019 MousePressed( vd, hwnd, MOUSE_BUTTON_LEFT );
1020 break;
1022 case WM_BUTTON2DOWN :
1023 MousePressed( vd, hwnd, MOUSE_BUTTON_RIGHT );
1024 break;
1026 case WM_BUTTON3DOWN :
1027 MousePressed( vd, hwnd, MOUSE_BUTTON_CENTER );
1028 break;
1030 case WM_BUTTON1UP :
1031 MouseReleased( vd, MOUSE_BUTTON_LEFT );
1032 break;
1034 case WM_BUTTON2UP :
1035 MouseReleased( vd, MOUSE_BUTTON_RIGHT );
1036 break;
1038 case WM_BUTTON3UP :
1039 MouseReleased( vd, MOUSE_BUTTON_CENTER );
1040 break;
1042 case WM_BUTTON1DBLCLK :
1043 vout_display_SendEventMouseDoubleClick(vd);
1044 break;
1046 case WM_TRANSLATEACCEL :
1047 /* We have no accelerator table at all */
1048 result = ( MRESULT )FALSE;
1049 break;
1051 case WM_CHAR :
1053 USHORT i_flags = SHORT1FROMMP( mp1 );
1054 USHORT i_ch = SHORT1FROMMP( mp2 );
1055 USHORT i_vk = SHORT2FROMMP( mp2 );
1056 int i_key = 0;
1058 /* If embedded window, let the parent process keys */
1059 if( sys->parent_window )
1061 WinPostMsg( sys->parent, msg, mp1, mp2 );
1062 break;
1065 if( !( i_flags & KC_KEYUP ))
1067 if( i_flags & KC_VIRTUALKEY )
1068 /* convert the key if possible */
1069 i_key = ConvertKey( i_vk );
1070 else if(( i_flags & KC_CHAR ) && !HIBYTE( i_ch ))
1071 i_key = tolower( i_ch );
1073 if( i_key )
1075 if( i_flags & KC_SHIFT )
1076 i_key |= KEY_MODIFIER_SHIFT;
1078 if( i_flags & KC_CTRL )
1079 i_key |= KEY_MODIFIER_CTRL;
1081 if( i_flags & KC_ALT )
1082 i_key |= KEY_MODIFIER_ALT;
1084 vout_display_SendEventKey(vd, i_key);
1087 break;
1090 /* Process Manage() call */
1091 case WM_VLC_MANAGE :
1092 break;
1094 /* Fullscreen change */
1095 case WM_VLC_FULLSCREEN_CHANGE :
1096 if( LONGFROMMP( mp1 ))
1098 WinQueryWindowPos( sys->frame, &swp );
1099 sys->client_rect.xLeft = swp.x;
1100 sys->client_rect.yBottom = swp.y;
1101 sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx;
1102 sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy;
1103 WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1105 rcl.xLeft = 0;
1106 rcl.yBottom = 0;
1107 rcl.xRight = sys->i_screen_width;
1108 rcl.yTop = sys->i_screen_height;
1110 else
1111 rcl = sys->client_rect;
1113 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1115 WinSetWindowPos( sys->frame, HWND_TOP,
1116 rcl.xLeft, rcl.yBottom,
1117 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1118 SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
1119 SWP_ACTIVATE );
1120 break;
1122 /* Size change */
1123 case WM_VLC_SIZE_CHANGE :
1124 rcl.xLeft = 0;
1125 rcl.yBottom = 0;
1126 rcl.xRight = LONGFROMMP( mp1 );
1127 rcl.yTop = LONGFROMMP( mp2 );
1128 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1130 WinSetWindowPos( sys->frame, NULLHANDLE,
1131 0, 0,
1132 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1133 SWP_SIZE );
1135 WinQueryWindowPos( sys->frame, &swp );
1136 sys->client_rect.xLeft = swp.x;
1137 sys->client_rect.yBottom = swp.y;
1138 sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx;
1139 sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy;
1140 WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1141 break;
1143 default :
1144 return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1147 /* If embedded window, we need to change our window size according to a
1148 * parent window size */
1149 if( sys->parent_window )
1151 WinQueryWindowRect( sys->parent, &rcl );
1153 if( rcl.xLeft != sys->parent_rect.xLeft ||
1154 rcl.yBottom != sys->parent_rect.yBottom ||
1155 rcl.xRight != sys->parent_rect.xRight ||
1156 rcl.yTop != sys->parent_rect.yTop)
1158 sys->parent_rect = rcl;
1160 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1162 WinSetWindowPos( sys->frame, NULLHANDLE,
1163 rcl.xLeft, rcl.yBottom,
1164 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1165 SWP_SIZE | SWP_MOVE );
1169 return result;