kva: support ZOOM
[vlc.git] / modules / video_output / kva.c
blobb90f431859c18bb916265442b06fe2ceff7a2a23
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 )
179 vout_window_cfg_t wnd_cfg;
181 wnd_cfg.is_standalone = false;
182 wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
183 wnd_cfg.x = var_InheritInteger(vd, "video-x");
184 wnd_cfg.y = var_InheritInteger(vd, "video-y");
185 wnd_cfg.width = vd->cfg->display.width;
186 wnd_cfg.height = vd->cfg->display.height;
188 /* If an external window was specified, we'll draw in it. */
189 sys->parent_window =
190 vout_display_NewWindow( vd, &wnd_cfg );
193 if( sys->parent_window )
195 sys->parent = ( HWND )sys->parent_window->handle.hwnd;
197 ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE );
198 WinSetWindowULong( sys->parent, QWL_STYLE,
199 i_style | WS_CLIPCHILDREN );
201 i_frame_flags = FCF_TITLEBAR;
203 else
205 sys->parent = HWND_DESKTOP;
207 i_frame_flags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX |
208 FCF_SIZEBORDER | FCF_TASKLIST;
211 sys->frame =
212 WinCreateStdWindow( sys->parent, /* parent window handle */
213 WS_VISIBLE, /* frame window style */
214 &i_frame_flags, /* window style */
215 WC_VLC_KVA, /* class name */
216 "", /* window title */
217 0L, /* default client style */
218 NULLHANDLE, /* resource in exe file */
219 1, /* frame window id */
220 &sys->client ); /* client window handle */
222 if( sys->frame == NULLHANDLE )
224 msg_Err( vd, "cannot create a frame window");
226 goto exit_frame;
229 WinSetWindowPtr( sys->client, 0, vd );
231 if( !sys->parent_window )
233 WinSetWindowPtr( sys->frame, 0, vd );
234 sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc );
237 psz_mode = var_CreateGetString( vd, "kva-video-mode" );
239 i_kva_mode = KVAM_AUTO;
240 if( strcmp( psz_mode, "snap" ) == 0 )
241 i_kva_mode = KVAM_SNAP;
242 else if( strcmp( psz_mode, "wo" ) == 0 )
243 i_kva_mode = KVAM_WO;
244 else if( strcmp( psz_mode, "vman" ) == 0 )
245 i_kva_mode = KVAM_VMAN;
246 else if( strcmp( psz_mode, "dive" ) == 0 )
247 i_kva_mode = KVAM_DIVE;
249 free( psz_mode );
251 if( kvaInit( i_kva_mode, sys->client, COLOR_KEY ))
253 msg_Err( vd, "cannot initialize KVA");
255 goto exit_kva_init;
258 kvaCaps( &sys->kvac );
260 msg_Dbg( vd, "selected video mode = %s",
261 psz_video_mode[ sys->kvac.ulMode - 1 ]);
263 if( OpenDisplay( vd, &fmt ) )
265 msg_Err( vd, "cannot open display");
267 goto exit_open_display;
270 if( vd->cfg->is_fullscreen )
272 if( sys->parent_window )
273 vout_window_SetFullScreen(sys->parent_window, true);
274 else
275 WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE,
276 MPFROMLONG( true ), 0 );
279 kvaDisableScreenSaver();
281 /* Setup vout_display now that everything is fine */
282 vd->fmt = fmt;
283 vd->info = info;
285 vd->pool = Pool;
286 vd->prepare = NULL;
287 vd->display = Display;
288 vd->control = Control;
289 vd->manage = Manage;
291 /* Prevent SIG_FPE */
292 _control87(MCW_EM, MCW_EM);
294 sys->i_result = VLC_SUCCESS;
295 DosPostEventSem( sys->ack_event );
297 if( !sys->parent_window )
298 WinSetVisibleRegionNotify( sys->frame, TRUE );
300 while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 ))
301 WinDispatchMsg( sys->hab, &qm );
303 if( !sys->parent_window )
304 WinSetVisibleRegionNotify( sys->frame, FALSE );
306 kvaEnableScreenSaver();
308 CloseDisplay( vd );
310 /* fall through */
312 exit_open_display :
313 kvaDone();
315 exit_kva_init :
316 if( !sys->parent_window )
317 WinSubclassWindow( sys->frame, sys->p_old_frame );
319 WinDestroyWindow( sys->frame );
321 exit_frame :
322 vout_display_DeleteWindow( vd, sys->parent_window );
324 if( sys->is_mouse_hidden )
325 WinShowPointer( HWND_DESKTOP, TRUE );
327 WinDestroyMsgQueue( sys->hmq );
328 WinTerminate( sys->hab );
330 sys->i_result = VLC_EGENERIC;
331 DosPostEventSem( sys->ack_event );
335 * This function initializes KVA vout method.
337 static int Open ( vlc_object_t *object )
339 vout_display_t *vd = (vout_display_t *)object;
340 vout_display_sys_t *sys;
342 vd->sys = sys = calloc( 1, sizeof( *sys ));
343 if( !sys )
344 return VLC_ENOMEM;
346 DosCreateEventSem( NULL, &sys->ack_event, 0, FALSE );
348 sys->tid = _beginthread( PMThread, NULL, 1024 * 1024, vd );
349 DosWaitEventSem( sys->ack_event, SEM_INDEFINITE_WAIT );
351 if( sys->i_result != VLC_SUCCESS )
353 DosCloseEventSem( sys->ack_event );
355 free( sys );
357 return VLC_EGENERIC;
360 return VLC_SUCCESS;
363 /*****************************************************************************
364 * Close: destroy KVA video thread output method
365 *****************************************************************************
366 * Terminate an output method created by Open
367 *****************************************************************************/
368 static void Close ( vlc_object_t *object )
370 vout_display_t * vd = (vout_display_t *)object;
371 vout_display_sys_t * sys = vd->sys;
373 WinPostQueueMsg( sys->hmq, WM_QUIT, 0, 0 );
375 DosWaitThread( &sys->tid, DCWW_WAIT );
377 if( sys->pool )
378 picture_pool_Delete( sys->pool );
380 DosCloseEventSem( sys->ack_event );
382 free( sys );
386 * Return a pool of direct buffers
388 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
390 vout_display_sys_t *sys = vd->sys;
391 VLC_UNUSED(count);
393 return sys->pool;
396 /*****************************************************************************
397 * Display: displays previously rendered output
398 *****************************************************************************
399 * This function sends the currently rendered image to the display.
400 *****************************************************************************/
401 static void Display( vout_display_t *vd, picture_t *picture,
402 subpicture_t *subpicture )
404 VLC_UNUSED( vd );
405 VLC_UNUSED( subpicture );
407 picture_Release( picture );
410 /*****************************************************************************
411 * Manage: handle Sys events
412 *****************************************************************************
413 * This function should be called regularly by video output thread. It returns
414 * a non null value if an error occurred.
415 *****************************************************************************/
416 static void Manage( vout_display_t *vd )
418 vout_display_sys_t * sys = vd->sys;
420 /* Let a window procedure manage instead because if resizing a frame window
421 * here, WM_SIZE is not sent to its child window.
422 * Maybe, is this due to the different threads ? */
423 WinPostMsg( sys->client, WM_VLC_MANAGE, 0, 0 );
426 /*****************************************************************************
427 * Control: control facility for the vout
428 *****************************************************************************/
429 static int Control( vout_display_t *vd, int query, va_list args )
431 vout_display_sys_t *sys = vd->sys;
433 switch (query)
435 case VOUT_DISPLAY_HIDE_MOUSE:
437 POINTL ptl;
439 WinQueryPointerPos( HWND_DESKTOP, &ptl );
440 if( !sys->is_mouse_hidden &&
441 WinWindowFromPoint( HWND_DESKTOP, &ptl, TRUE ) == sys->client )
443 WinShowPointer( HWND_DESKTOP, FALSE );
444 sys->is_mouse_hidden = true;
447 return VLC_SUCCESS;
450 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
452 vout_display_cfg_t cfg = *va_arg(args, const vout_display_cfg_t *);
454 if( sys->parent_window )
455 vout_window_SetFullScreen(sys->parent_window, cfg.is_fullscreen);
456 else
457 WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE,
458 MPFROMLONG( cfg.is_fullscreen ), 0 );
460 return VLC_SUCCESS;
463 case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
465 const unsigned state = va_arg( args, unsigned );
466 const bool is_on_top = (state & VOUT_WINDOW_STATE_ABOVE) != 0;
468 if( sys->parent_window )
470 if( vout_window_SetState( sys->parent_window, state ))
471 return VLC_EGENERIC;
473 else if( is_on_top )
474 WinSetWindowPos( sys->frame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
476 sys->is_on_top = is_on_top;
478 return VLC_SUCCESS;
481 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
482 case VOUT_DISPLAY_CHANGE_ZOOM:
484 const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
485 bool is_forced = query == VOUT_DISPLAY_CHANGE_ZOOM ||
486 va_arg(args, int);
488 if( is_forced )
490 if( sys->parent_window )
492 vout_window_SetSize(sys->parent_window,
493 cfg->display.width, cfg->display.height);
495 else
496 WinPostMsg( sys->client, WM_VLC_SIZE_CHANGE,
497 MPFROMLONG( cfg->display.width ),
498 MPFROMLONG( cfg->display.height ));
501 return VLC_SUCCESS;
504 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
505 case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
507 const video_format_t *src = va_arg(args, const video_format_t *);
509 if( query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT )
511 vout_display_place_t place;
512 vout_display_PlacePicture(&place, src, vd->cfg, false);
514 sys->kvas.ulAspectWidth = place.width;
515 sys->kvas.ulAspectHeight = place.height;
517 else
519 video_format_t src_rot;
520 video_format_ApplyRotation(&src_rot, src);
522 sys->kvas.rclSrcRect.xLeft = src_rot.i_x_offset;
523 sys->kvas.rclSrcRect.yTop = src_rot.i_y_offset;
524 sys->kvas.rclSrcRect.xRight = src_rot.i_x_offset +
525 src_rot.i_visible_width;
526 sys->kvas.rclSrcRect.yBottom = src_rot.i_y_offset +
527 src_rot.i_visible_height;
530 kvaSetup( &sys->kvas );
532 return VLC_SUCCESS;
535 case VOUT_DISPLAY_RESET_PICTURES:
536 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
537 case VOUT_DISPLAY_GET_OPENGL:
538 /* TODO */
539 break;
542 msg_Err(vd, "Unsupported query(=%d) in vout display KVA", query);
543 return VLC_EGENERIC;
546 /* following functions are local */
548 /*****************************************************************************
549 * OpenDisplay: open and initialize KVA device
550 *****************************************************************************
551 * Open and initialize display according to preferences specified in the vout
552 * thread fields.
553 *****************************************************************************/
554 static int OpenDisplay( vout_display_t *vd, video_format_t *fmt )
556 vout_display_sys_t * sys = vd->sys;
557 const vlc_fourcc_t *fallback;
558 bool b_hw_accel = 0;
559 FOURCC i_kva_fourcc;
560 int i_chroma_shift;
561 char sz_title[ 256 ];
562 RECTL rcl;
563 int w, h;
565 msg_Dbg( vd, "render chroma = %4.4s", ( const char * )&fmt->i_chroma );
567 for( int pass = 0; pass < 2 && !b_hw_accel; pass++ )
569 fallback = ( pass == 0 ) ? vlc_fourcc_GetYUVFallback( fmt->i_chroma ) :
570 vlc_fourcc_GetRGBFallback( fmt->i_chroma );
572 for( int i = 0; fallback[ i ]; i++ )
574 switch( fallback[ i ])
576 case VLC_CODEC_YV12:
577 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12;
578 i_kva_fourcc = FOURCC_YV12;
579 i_chroma_shift = 1;
580 break;
582 case VLC_CODEC_YUYV:
583 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YUY2;
584 i_kva_fourcc = FOURCC_Y422;
585 i_chroma_shift = 0;
586 break;
588 case VLC_CODEC_YV9:
589 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YVU9;
590 i_kva_fourcc = FOURCC_YVU9;
591 i_chroma_shift = 2;
592 break;
594 case VLC_CODEC_RGB32:
595 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR32;
596 i_kva_fourcc = FOURCC_BGR4;
597 i_chroma_shift = 0;
598 break;
600 case VLC_CODEC_RGB24:
601 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR24;
602 i_kva_fourcc = FOURCC_BGR3;
603 i_chroma_shift = 0;
604 break;
606 case VLC_CODEC_RGB16:
607 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR16;
608 i_kva_fourcc = FOURCC_R565;
609 i_chroma_shift = 0;
610 break;
612 case VLC_CODEC_RGB15:
613 b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR15;
614 i_kva_fourcc = FOURCC_R555;
615 i_chroma_shift = 0;
616 break;
619 if( b_hw_accel )
621 fmt->i_chroma = fallback[ i ];
622 break;
627 if( !b_hw_accel )
629 msg_Err( vd, "Ooops. There is no fourcc supported by KVA at all.");
631 return VLC_EGENERIC;
634 /* Set the RGB masks */
635 fmt->i_rmask = sys->kvac.ulRMask;
636 fmt->i_gmask = sys->kvac.ulGMask;
637 fmt->i_bmask = sys->kvac.ulBMask;
639 msg_Dbg( vd, "output chroma = %4.4s", ( const char * )&fmt->i_chroma );
640 msg_Dbg( vd, "KVA chroma = %4.4s", ( const char * )&i_kva_fourcc );
642 w = fmt->i_width;
643 h = fmt->i_height;
645 sys->kvas.ulLength = sizeof( KVASETUP );
646 sys->kvas.szlSrcSize.cx = w;
647 sys->kvas.szlSrcSize.cy = h;
648 sys->kvas.rclSrcRect.xLeft = 0;
649 sys->kvas.rclSrcRect.yTop = 0;
650 sys->kvas.rclSrcRect.xRight = w;
651 sys->kvas.rclSrcRect.yBottom = h;
652 sys->kvas.ulRatio = KVAR_FORCEANY;
653 sys->kvas.ulAspectWidth = w;
654 sys->kvas.ulAspectHeight = h;
655 sys->kvas.fccSrcColor = i_kva_fourcc;
656 sys->kvas.fDither = TRUE;
658 if( kvaSetup( &sys->kvas ))
660 msg_Err( vd, "cannot set up KVA");
662 return VLC_EGENERIC;
665 /* Create the associated picture */
666 picture_sys_t *picsys = malloc( sizeof( *picsys ) );
667 if( picsys == NULL )
668 return VLC_ENOMEM;
669 picsys->i_chroma_shift = i_chroma_shift;
671 picture_resource_t resource = { .p_sys = picsys };
672 picture_t *picture = picture_NewFromResource( fmt, &resource );
673 if( !picture )
675 free( picsys );
676 return VLC_ENOMEM;
679 /* Wrap it into a picture pool */
680 picture_pool_configuration_t pool_cfg;
681 memset( &pool_cfg, 0, sizeof( pool_cfg ));
682 pool_cfg.picture_count = 1;
683 pool_cfg.picture = &picture;
684 pool_cfg.lock = KVALock;
685 pool_cfg.unlock = KVAUnlock;
687 sys->pool = picture_pool_NewExtended( &pool_cfg );
688 if( !sys->pool )
690 picture_Release( picture );
691 return VLC_ENOMEM;
694 if (vd->cfg->display.title)
695 snprintf( sz_title, sizeof( sz_title ), "%s", vd->cfg->display.title );
696 else
697 snprintf( sz_title, sizeof( sz_title ),
698 "%s (%4.4s to %4.4s - %s mode KVA output)",
699 VOUT_TITLE,
700 ( char * )&vd->fmt.i_chroma,
701 ( char * )&sys->kvas.fccSrcColor,
702 psz_video_mode[ sys->kvac.ulMode - 1 ]);
703 WinSetWindowText( sys->frame, sz_title );
705 sys->i_screen_width = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
706 sys->i_screen_height = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
708 if( sys->parent_window )
709 WinQueryWindowRect( sys->parent, &sys->client_rect );
710 else
712 sys->client_rect.xLeft = ( sys->i_screen_width - w ) / 2;
713 sys->client_rect.yBottom = ( sys->i_screen_height - h ) / 2 ;
714 sys->client_rect.xRight = sys->client_rect.xLeft + w;
715 sys->client_rect.yTop = sys->client_rect.yBottom + h;
718 rcl = sys->client_rect;
720 WinCalcFrameRect( sys->frame, &rcl, FALSE);
722 WinSetWindowPos( sys->frame, HWND_TOP,
723 rcl.xLeft, rcl.yBottom,
724 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
725 SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
726 SWP_ACTIVATE );
728 return VLC_SUCCESS;
731 /*****************************************************************************
732 * CloseDisplay: close and reset KVA device
733 *****************************************************************************
734 * This function returns all resources allocated by OpenDisplay and restore
735 * the original state of the device.
736 *****************************************************************************/
737 static void CloseDisplay( vout_display_t *vd )
739 VLC_UNUSED( vd );
742 static int KVALock( picture_t *picture )
744 picture_sys_t *picsys = picture->p_sys;
745 PVOID kva_buffer;
746 ULONG kva_bpl;
748 if( kvaLockBuffer( &kva_buffer, &kva_bpl ))
749 return VLC_EGENERIC;
751 /* Packed or Y plane */
752 picture->p->p_pixels = ( uint8_t * )kva_buffer;
753 picture->p->i_pitch = kva_bpl;
754 picture->p->i_lines = picture->format.i_height;
756 /* Other planes */
757 for( int n = 1; n < picture->i_planes; n++ )
759 const plane_t *o = &picture->p[n-1];
760 plane_t *p = &picture->p[n];
762 p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
763 p->i_pitch = kva_bpl >> picsys->i_chroma_shift;
764 p->i_lines = picture->format.i_height >> picsys->i_chroma_shift;
767 return VLC_SUCCESS;
770 static void KVAUnlock( picture_t *picture )
772 VLC_UNUSED( picture );
774 kvaUnlockBuffer();
777 static void MorphToPM( void )
779 PPIB pib;
781 DosGetInfoBlocks(NULL, &pib);
783 /* Change flag from VIO to PM */
784 if (pib->pib_ultype == 2)
785 pib->pib_ultype = 3;
788 /*****************************************************************************
789 * Key events handling
790 *****************************************************************************/
791 static const struct
793 USHORT i_pmkey;
794 int i_vlckey;
795 } pmkeys_to_vlckeys[] =
797 { VK_LEFT, KEY_LEFT },
798 { VK_RIGHT, KEY_RIGHT },
799 { VK_UP, KEY_UP },
800 { VK_DOWN, KEY_DOWN },
801 { VK_SPACE, ' ' },
802 { VK_NEWLINE, KEY_ENTER },
803 { VK_ENTER, KEY_ENTER },
804 { VK_F1, KEY_F1 },
805 { VK_F2, KEY_F2 },
806 { VK_F3, KEY_F3 },
807 { VK_F4, KEY_F4 },
808 { VK_F5, KEY_F5 },
809 { VK_F6, KEY_F6 },
810 { VK_F7, KEY_F7 },
811 { VK_F8, KEY_F8 },
812 { VK_F9, KEY_F9 },
813 { VK_F10, KEY_F10 },
814 { VK_F11, KEY_F11 },
815 { VK_F12, KEY_F12 },
816 { VK_HOME, KEY_HOME },
817 { VK_END, KEY_END },
818 { VK_INSERT, KEY_INSERT },
819 { VK_DELETE, KEY_DELETE },
821 Not supported
822 {, KEY_MENU },
824 { VK_ESC, KEY_ESC },
825 { VK_PAGEUP, KEY_PAGEUP },
826 { VK_PAGEDOWN, KEY_PAGEDOWN },
827 { VK_TAB, KEY_TAB },
828 { VK_BACKSPACE, KEY_BACKSPACE },
830 Not supported
831 {, KEY_MOUSEWHEELUP },
832 {, KEY_MOUSEWHEELDOWN },
833 {, KEY_MOUSEWHEELLEFT },
834 {, KEY_MOUSEWHEELRIGHT },
836 {, KEY_BROWSER_BACK },
837 {, KEY_BROWSER_FORWARD },
838 {, KEY_BROWSER_REFRESH },
839 {, KEY_BROWSER_STOP },
840 {, KEY_BROWSER_SEARCH },
841 {, KEY_BROWSER_FAVORITES },
842 {, KEY_BROWSER_HOME },
843 {, KEY_VOLUME_MUTE },
844 {, KEY_VOLUME_DOWN },
845 {, KEY_VOLUME_UP },
846 {, KEY_MEDIA_NEXT_TRACK },
847 {, KEY_MEDIA_PREV_TRACK },
848 {, KEY_MEDIA_STOP },
849 {, KEY_MEDIA_PLAY_PAUSE },
852 { 0, 0 }
855 static int ConvertKey( USHORT i_pmkey )
857 int i;
858 for( i = 0; pmkeys_to_vlckeys[ i ].i_pmkey != 0; i++ )
860 if( pmkeys_to_vlckeys[ i ].i_pmkey == i_pmkey )
861 return pmkeys_to_vlckeys[ i ].i_vlckey;
863 return 0;
866 static MRESULT EXPENTRY MyFrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1,
867 MPARAM mp2 )
869 vout_display_t *vd = WinQueryWindowPtr( hwnd, 0 );
870 vout_display_sys_t *sys = vd->sys;
872 switch( msg )
874 case WM_QUERYTRACKINFO :
876 MRESULT mr;
878 mr = sys->p_old_frame( hwnd, msg, mp1, mp2 );
879 if( !sys->b_fixt23 )
880 return mr;
882 PTRACKINFO pti = ( PTRACKINFO )mp2;
883 RECTL rcl;
885 pti->rclBoundary.xLeft = 0;
886 pti->rclBoundary.yBottom = 0;
887 pti->rclBoundary.xRight = sys->i_screen_width;
888 pti->rclBoundary.yTop = sys->i_screen_height;
890 WinCalcFrameRect( hwnd, &pti->rclBoundary, FALSE );
892 pti->ptlMaxTrackSize.x = pti->rclBoundary.xRight -
893 pti->rclBoundary.xLeft;
894 pti->ptlMaxTrackSize.y = pti->rclBoundary.yTop -
895 pti->rclBoundary.yBottom;
897 rcl.xLeft = 0;
898 rcl.yBottom = 0;
899 rcl.xRight = sys->kvas.szlSrcSize.cx + 1;
900 rcl.yTop = sys->kvas.szlSrcSize.cy + 1;
902 WinCalcFrameRect( hwnd, &rcl, FALSE );
904 pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft;
905 pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom;
907 return MRFROMLONG( TRUE );
910 case WM_ADJUSTWINDOWPOS :
912 if( !sys->b_fixt23 )
913 break;
915 PSWP pswp = ( PSWP )mp1;
917 if( pswp->fl & SWP_SIZE )
919 RECTL rcl;
921 rcl.xLeft = pswp->x;
922 rcl.yBottom = pswp->y;
923 rcl.xRight = rcl.xLeft + pswp->cx;
924 rcl.yTop = rcl.yBottom + pswp->cy;
926 WinCalcFrameRect( hwnd, &rcl, TRUE );
928 if( rcl.xRight - rcl.xLeft <= sys->kvas.szlSrcSize.cx )
929 rcl.xRight = rcl.xLeft + ( sys->kvas.szlSrcSize.cx + 1 );
931 if( rcl.yTop - rcl.yBottom <= sys->kvas.szlSrcSize.cy )
932 rcl.yTop = rcl.yBottom + ( sys->kvas.szlSrcSize.cy + 1 );
934 if( rcl.xRight - rcl.xLeft > sys->i_screen_width )
936 rcl.xLeft = 0;
937 rcl.xRight = sys->i_screen_width;
940 if( rcl.yTop - rcl.yBottom > sys->i_screen_height )
942 rcl.yBottom = 0;
943 rcl.yTop = sys->i_screen_height;
946 WinCalcFrameRect( hwnd, &rcl, FALSE );
948 if( pswp->x != rcl.xLeft || pswp->y != rcl.yBottom )
949 pswp->fl |= SWP_MOVE;
951 pswp->x = rcl.xLeft;
952 pswp->y = rcl.yBottom;
954 pswp->cx = rcl.xRight - rcl.xLeft;
955 pswp->cy = rcl.yTop - rcl.yBottom;
958 break;
961 //case WM_VRNDISABLED :
962 case WM_VRNENABLED :
963 if( !vd->cfg->is_fullscreen && sys->is_on_top )
964 WinSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
965 break;
968 return sys->p_old_frame( hwnd, msg, mp1, mp2 );
971 static void MousePressed( vout_display_t *vd, HWND hwnd, unsigned button )
973 if( WinQueryFocus( HWND_DESKTOP ) != hwnd )
974 WinSetFocus( HWND_DESKTOP, hwnd );
976 if( !vd->sys->button_pressed )
977 WinSetCapture( HWND_DESKTOP, hwnd );
979 vd->sys->button_pressed |= 1 << button;
981 vout_display_SendEventMousePressed( vd, button );
984 static void MouseReleased( vout_display_t *vd, unsigned button )
986 vd->sys->button_pressed &= ~(1 << button);
987 if( !vd->sys->button_pressed )
988 WinSetCapture( HWND_DESKTOP, NULLHANDLE );
990 vout_display_SendEventMouseReleased( vd, button );
993 #define WM_MOUSELEAVE 0x41F
995 static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
997 vout_display_t * vd = WinQueryWindowPtr( hwnd, 0 );
998 MRESULT result = ( MRESULT )TRUE;
1000 if ( !vd )
1001 return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1003 vout_display_sys_t * sys = vd->sys;
1004 RECTL rcl;
1005 SWP swp;
1007 if ( sys->is_mouse_hidden &&
1008 ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
1009 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST) ||
1010 msg == WM_MOUSELEAVE))
1012 WinShowPointer(HWND_DESKTOP, TRUE);
1013 sys->is_mouse_hidden = false;
1016 switch( msg )
1018 /* the user wants to close the window */
1019 case WM_CLOSE:
1020 vout_display_SendEventClose(vd);
1021 result = 0;
1022 break;
1024 case WM_MOUSEMOVE :
1026 SHORT i_mouse_x = SHORT1FROMMP( mp1 );
1027 SHORT i_mouse_y = SHORT2FROMMP( mp1 );
1028 RECTL movie_rect;
1029 int i_movie_width, i_movie_height;
1030 int i_src_width, i_src_height;
1032 /* Get a current movie area */
1033 kvaAdjustDstRect( &sys->kvas.rclSrcRect, &movie_rect );
1034 i_movie_width = movie_rect.xRight - movie_rect.xLeft;
1035 i_movie_height = movie_rect.yTop - movie_rect.yBottom;
1037 i_src_width = sys->kvas.rclSrcRect.xRight -
1038 sys->kvas.rclSrcRect.xLeft;
1039 i_src_height = sys->kvas.rclSrcRect.yBottom -
1040 sys->kvas.rclSrcRect.yTop;
1042 int x = ( i_mouse_x - movie_rect.xLeft ) *
1043 i_src_width / i_movie_width +
1044 sys->kvas.rclSrcRect.xLeft;
1045 int y = ( i_mouse_y - movie_rect.yBottom ) *
1046 i_src_height / i_movie_height;
1048 /* Invert Y coordinate and add y offset */
1049 y = ( i_src_height - y ) + sys->kvas.rclSrcRect.yTop;;
1051 vout_display_SendEventMouseMoved(vd, x, y);
1053 result = WinDefWindowProc( hwnd, msg, mp1,mp2 );
1054 break;
1057 case WM_BUTTON1DOWN :
1058 MousePressed( vd, hwnd, MOUSE_BUTTON_LEFT );
1059 break;
1061 case WM_BUTTON2DOWN :
1062 MousePressed( vd, hwnd, MOUSE_BUTTON_RIGHT );
1063 break;
1065 case WM_BUTTON3DOWN :
1066 MousePressed( vd, hwnd, MOUSE_BUTTON_CENTER );
1067 break;
1069 case WM_BUTTON1UP :
1070 MouseReleased( vd, MOUSE_BUTTON_LEFT );
1071 break;
1073 case WM_BUTTON2UP :
1074 MouseReleased( vd, MOUSE_BUTTON_RIGHT );
1075 break;
1077 case WM_BUTTON3UP :
1078 MouseReleased( vd, MOUSE_BUTTON_CENTER );
1079 break;
1081 case WM_BUTTON1DBLCLK :
1082 vout_display_SendEventMouseDoubleClick(vd);
1083 break;
1085 case WM_TRANSLATEACCEL :
1086 /* We have no accelerator table at all */
1087 result = ( MRESULT )FALSE;
1088 break;
1090 case WM_CHAR :
1092 USHORT i_flags = SHORT1FROMMP( mp1 );
1093 USHORT i_ch = SHORT1FROMMP( mp2 );
1094 USHORT i_vk = SHORT2FROMMP( mp2 );
1095 int i_key = 0;
1097 /* If embedded window, let the parent process keys */
1098 if( sys->parent_window )
1100 WinPostMsg( sys->parent, msg, mp1, mp2 );
1101 break;
1104 if( !( i_flags & KC_KEYUP ))
1106 if( i_flags & KC_VIRTUALKEY )
1107 /* convert the key if possible */
1108 i_key = ConvertKey( i_vk );
1109 else if(( i_flags & KC_CHAR ) && !HIBYTE( i_ch ))
1110 i_key = tolower( i_ch );
1112 if( i_key )
1114 if( i_flags & KC_SHIFT )
1115 i_key |= KEY_MODIFIER_SHIFT;
1117 if( i_flags & KC_CTRL )
1118 i_key |= KEY_MODIFIER_CTRL;
1120 if( i_flags & KC_ALT )
1121 i_key |= KEY_MODIFIER_ALT;
1123 vout_display_SendEventKey(vd, i_key);
1126 break;
1129 /* Process Manage() call */
1130 case WM_VLC_MANAGE :
1131 break;
1133 /* Fullscreen change */
1134 case WM_VLC_FULLSCREEN_CHANGE :
1135 if( LONGFROMMP( mp1 ))
1137 WinQueryWindowPos( sys->frame, &swp );
1138 sys->client_rect.xLeft = swp.x;
1139 sys->client_rect.yBottom = swp.y;
1140 sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx;
1141 sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy;
1142 WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1144 rcl.xLeft = 0;
1145 rcl.yBottom = 0;
1146 rcl.xRight = sys->i_screen_width;
1147 rcl.yTop = sys->i_screen_height;
1149 else
1150 rcl = sys->client_rect;
1152 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1154 WinSetWindowPos( sys->frame, HWND_TOP,
1155 rcl.xLeft, rcl.yBottom,
1156 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1157 SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
1158 SWP_ACTIVATE );
1159 break;
1161 /* Size change */
1162 case WM_VLC_SIZE_CHANGE :
1163 rcl.xLeft = 0;
1164 rcl.yBottom = 0;
1165 rcl.xRight = LONGFROMMP( mp1 );
1166 rcl.yTop = LONGFROMMP( mp2 );
1167 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1169 WinSetWindowPos( sys->frame, NULLHANDLE,
1170 0, 0,
1171 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1172 SWP_SIZE );
1174 WinQueryWindowPos( sys->frame, &swp );
1175 sys->client_rect.xLeft = swp.x;
1176 sys->client_rect.yBottom = swp.y;
1177 sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx;
1178 sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy;
1179 WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1180 break;
1182 default :
1183 return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1186 /* If embedded window, we need to change our window size according to a
1187 * parent window size */
1188 if( sys->parent_window )
1190 WinQueryWindowRect( sys->parent, &rcl );
1192 if( rcl.xLeft != sys->parent_rect.xLeft ||
1193 rcl.yBottom != sys->parent_rect.yBottom ||
1194 rcl.xRight != sys->parent_rect.xRight ||
1195 rcl.yTop != sys->parent_rect.yTop)
1197 sys->parent_rect = rcl;
1199 WinCalcFrameRect( sys->frame, &rcl, FALSE );
1201 WinSetWindowPos( sys->frame, NULLHANDLE,
1202 rcl.xLeft, rcl.yBottom,
1203 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1204 SWP_SIZE | SWP_MOVE );
1208 return result;