1 /*****************************************************************************
2 * events.c: Windows DirectX video output events handler
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble: This file contains the functions related to the creation of
27 * a window and the handling of its messages (events).
28 *****************************************************************************/
33 #include <errno.h> /* ENOMEM */
34 #include <ctype.h> /* tolower() */
37 # define _WIN32_WINNT 0x0500
40 #include <vlc_common.h>
41 #include <vlc_interface.h>
42 #include <vlc_playlist.h>
44 #include <vlc_vout_window.h>
51 #ifdef MODULE_NAME_IS_directx
54 #ifdef MODULE_NAME_IS_direct3d
57 #ifdef MODULE_NAME_IS_glwin32
66 //WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState);
69 /*#if defined(UNDER_CE) && !defined(__PLUGIN__) --FIXME*/
70 /*# define SHFS_SHOWSIPBUTTON 0x0004
71 # define SHFS_HIDESIPBUTTON 0x0008
72 # define MENU_HEIGHT 26
73 BOOL SHFullScreen(HWND hwndRequester, DWORD dwState);
77 /*****************************************************************************
79 *****************************************************************************/
80 static int DirectXCreateWindow( vout_thread_t *p_vout );
81 static void DirectXCloseWindow ( vout_thread_t *p_vout );
82 static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
84 static void DirectXPopupMenu( event_thread_t *p_event, bool b_open )
88 var_Set( p_event->p_vout->p_libvlc, "intf-popupmenu", val );
91 static int DirectXConvertKey( int i_key );
93 /*****************************************************************************
94 * EventThread: Create video window & handle its messages
95 *****************************************************************************
96 * This function creates a video window and then enters an infinite loop
97 * that handles the messages sent to that window.
98 * The main goal of this thread is to isolate the Win32 PeekMessage function
99 * because this one can block for a long time.
100 *****************************************************************************/
101 static void *EventThread( void *p_this )
103 event_thread_t *p_event = (event_thread_t *)p_this;
104 vout_thread_t *p_vout = p_event->p_vout;
106 POINT old_mouse_pos = {0,0}, mouse_pos;
108 unsigned int i_width, i_height, i_x, i_y;
110 int canc = vlc_savecancel ();
112 vlc_mutex_lock( &p_event->lock );
113 /* Create a window for the video */
114 /* Creating a window under Windows also initializes the thread's event
116 if( DirectXCreateWindow( p_event->p_vout ) )
117 p_event->b_error = true;
119 p_event->b_ready = true;
120 vlc_cond_signal( &p_event->wait );
122 const bool b_error = p_event->b_error;
123 vlc_mutex_unlock( &p_event->lock );
127 vlc_restorecancel( canc );
132 /* Set power management stuff */
133 if( (hkernel32 = GetModuleHandle( _T("KERNEL32") ) ) )
135 ULONG (WINAPI* OurSetThreadExecutionState)( ULONG );
137 OurSetThreadExecutionState = (ULONG (WINAPI*)( ULONG ))
138 GetProcAddress( hkernel32, _T("SetThreadExecutionState") );
140 if( OurSetThreadExecutionState )
141 /* Prevent monitor from powering off */
142 OurSetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
144 msg_Dbg( p_vout, "no support for SetThreadExecutionState()" );
149 /* GetMessage will sleep if there's no message in the queue */
152 if( !GetMessage( &msg, 0, 0, 0 ) )
154 vlc_mutex_lock( &p_event->lock );
155 p_event->b_done = true;
156 vlc_mutex_unlock( &p_event->lock );
160 /* Check if we are asked to exit */
161 vlc_mutex_lock( &p_event->lock );
162 const bool b_done = p_event->b_done;
163 vlc_mutex_unlock( &p_event->lock );
168 switch( msg.message )
172 vout_PlacePicture( p_event->p_vout,
173 p_event->p_vout->p_sys->i_window_width,
174 p_event->p_vout->p_sys->i_window_height,
175 &i_x, &i_y, &i_width, &i_height );
177 if( msg.hwnd == p_event->p_vout->p_sys->hvideownd )
183 if( i_width && i_height )
185 val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x ) *
186 p_event->p_vout->fmt_in.i_visible_width / i_width +
187 p_event->p_vout->fmt_in.i_x_offset;
188 var_Set( p_event->p_vout, "mouse-x", val );
189 val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y ) *
190 p_event->p_vout->fmt_in.i_visible_height / i_height +
191 p_event->p_vout->fmt_in.i_y_offset;
192 var_Set( p_event->p_vout, "mouse-y", val );
194 var_SetBool( p_event->p_vout, "mouse-moved", true );
198 GetCursorPos( &mouse_pos );
199 if( (abs(mouse_pos.x - old_mouse_pos.x) > 2 ||
200 (abs(mouse_pos.y - old_mouse_pos.y)) > 2 ) )
202 GetCursorPos( &old_mouse_pos );
203 p_event->p_vout->p_sys->i_lastmoved = mdate();
205 if( p_event->p_vout->p_sys->b_cursor_hidden )
207 p_event->p_vout->p_sys->b_cursor_hidden = 0;
213 case WM_VLC_HIDE_MOUSE:
214 if( p_event->p_vout->p_sys->b_cursor_hidden ) break;
215 p_event->p_vout->p_sys->b_cursor_hidden = true;
216 GetCursorPos( &old_mouse_pos );
220 case WM_VLC_SHOW_MOUSE:
221 if( !p_event->p_vout->p_sys->b_cursor_hidden ) break;
222 p_event->p_vout->p_sys->b_cursor_hidden = false;
223 GetCursorPos( &old_mouse_pos );
228 var_Get( p_event->p_vout, "mouse-button-down", &val );
230 var_Set( p_event->p_vout, "mouse-button-down", val );
231 DirectXPopupMenu( p_event, false );
235 var_Get( p_event->p_vout, "mouse-button-down", &val );
237 var_Set( p_event->p_vout, "mouse-button-down", val );
239 var_SetBool( p_event->p_vout, "mouse-clicked", true );
242 case WM_LBUTTONDBLCLK:
243 p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
247 var_Get( p_event->p_vout, "mouse-button-down", &val );
249 var_Set( p_event->p_vout, "mouse-button-down", val );
250 DirectXPopupMenu( p_event, false );
254 var_Get( p_event->p_vout, "mouse-button-down", &val );
256 var_Set( p_event->p_vout, "mouse-button-down", val );
260 var_Get( p_event->p_vout, "mouse-button-down", &val );
262 var_Set( p_event->p_vout, "mouse-button-down", val );
263 DirectXPopupMenu( p_event, false );
267 var_Get( p_event->p_vout, "mouse-button-down", &val );
269 var_Set( p_event->p_vout, "mouse-button-down", val );
270 DirectXPopupMenu( p_event, true );
275 /* The key events are first processed here and not translated
276 * into WM_CHAR events because we need to know the status of the
278 val.i_int = DirectXConvertKey( msg.wParam );
281 /* This appears to be a "normal" (ascii) key */
282 val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) );
287 if( GetKeyState(VK_CONTROL) & 0x8000 )
289 val.i_int |= KEY_MODIFIER_CTRL;
291 if( GetKeyState(VK_SHIFT) & 0x8000 )
293 val.i_int |= KEY_MODIFIER_SHIFT;
295 if( GetKeyState(VK_MENU) & 0x8000 )
297 val.i_int |= KEY_MODIFIER_ALT;
300 var_Set( p_vout->p_libvlc, "key-pressed", val );
305 if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 )
307 val.i_int = KEY_MOUSEWHEELUP;
311 val.i_int = KEY_MOUSEWHEELDOWN;
315 if( GetKeyState(VK_CONTROL) & 0x8000 )
317 val.i_int |= KEY_MODIFIER_CTRL;
319 if( GetKeyState(VK_SHIFT) & 0x8000 )
321 val.i_int |= KEY_MODIFIER_SHIFT;
323 if( GetKeyState(VK_MENU) & 0x8000 )
325 val.i_int |= KEY_MODIFIER_ALT;
328 var_Set( p_vout->p_libvlc, "key-pressed", val );
332 case WM_VLC_CHANGE_TEXT:
333 var_Get( p_vout, "video-title", &val );
334 if( !val.psz_string || !*val.psz_string ) /* Default video title */
336 free( val.psz_string );
338 #ifdef MODULE_NAME_IS_wingdi
339 val.psz_string = strdup( VOUT_TITLE " (WinGDI output)" );
341 #ifdef MODULE_NAME_IS_wingapi
342 val.psz_string = strdup( VOUT_TITLE " (WinGAPI output)" );
344 #ifdef MODULE_NAME_IS_glwin32
345 val.psz_string = strdup( VOUT_TITLE " (OpenGL output)" );
347 #ifdef MODULE_NAME_IS_direct3d
348 val.psz_string = strdup( VOUT_TITLE " (Direct3D output)" );
350 #ifdef MODULE_NAME_IS_directx
351 if( p_event->p_vout->p_sys->b_using_overlay ) val.psz_string =
352 strdup( VOUT_TITLE " (hardware YUV overlay DirectX output)" );
353 else if( p_event->p_vout->p_sys->b_hw_yuv ) val.psz_string =
354 strdup( VOUT_TITLE " (hardware YUV DirectX output)" );
355 else val.psz_string =
356 strdup( VOUT_TITLE " (software RGB DirectX output)" );
361 wchar_t *psz_title = malloc( strlen(val.psz_string) * 2 + 2 );
364 mbstowcs( psz_title, val.psz_string, strlen(val.psz_string)*2);
365 psz_title[strlen(val.psz_string)] = 0;
366 free( val.psz_string ); val.psz_string = (char *)psz_title;
370 SetWindowText( p_event->p_vout->p_sys->hwnd,
371 (LPCTSTR)val.psz_string );
372 if( p_event->p_vout->p_sys->hfswnd )
373 SetWindowText( p_event->p_vout->p_sys->hfswnd,
374 (LPCTSTR)val.psz_string );
375 free( val.psz_string );
379 /* Messages we don't handle directly are dispatched to the
380 * window procedure */
381 TranslateMessage(&msg);
382 DispatchMessage(&msg);
387 } /* End Main loop */
389 /* Check for WM_QUIT if we created the window */
390 if( !p_event->p_vout->p_sys->hparent && msg.message == WM_QUIT )
392 msg_Warn( p_vout, "WM_QUIT... should not happen!!" );
393 p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
396 msg_Dbg( p_vout, "DirectXEventThread terminating" );
398 DirectXCloseWindow( p_event->p_vout );
399 vlc_restorecancel(canc);
404 /* following functions are local */
406 /*****************************************************************************
407 * DirectXCreateWindow: create a window for the video.
408 *****************************************************************************
409 * Before creating a direct draw surface, we need to create a window in which
410 * the video will be displayed. This window will also allow us to capture the
412 *****************************************************************************/
413 static int DirectXCreateWindow( vout_thread_t *p_vout )
418 WNDCLASS wc; /* window class components */
419 HICON vlc_icon = NULL;
420 char vlc_path[MAX_PATH+1];
421 int i_style, i_stylex;
423 msg_Dbg( p_vout, "DirectXCreateWindow" );
425 /* Get this module's instance */
426 hInstance = GetModuleHandle(NULL);
428 #ifdef MODULE_NAME_IS_direct3d
429 if( !p_vout->p_sys->b_desktop )
432 vout_window_cfg_t wnd_cfg;
433 memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
434 wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
435 wnd_cfg.x = p_vout->p_sys->i_window_x;
436 wnd_cfg.y = p_vout->p_sys->i_window_y;
437 wnd_cfg.width = p_vout->p_sys->i_window_width;
438 wnd_cfg.height = p_vout->p_sys->i_window_height;
440 /* If an external window was specified, we'll draw in it. */
441 p_vout->p_sys->parent_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &wnd_cfg );
442 if( p_vout->p_sys->parent_window )
443 p_vout->p_sys->hparent = p_vout->p_sys->parent_window->handle.hwnd;
444 #ifdef MODULE_NAME_IS_direct3d
448 /* Find Program Manager */
449 HWND hwnd = FindWindow( _T("Progman"), NULL );
450 if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL );
451 if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL );
453 msg_Err( p_vout, "Couldn't find desktop icon window. Desktop mode can't be established." );
454 p_vout->p_sys->hparent = hwnd;
458 /* We create the window ourself, there is no previous window proc. */
459 p_vout->p_sys->pf_wndproc = NULL;
461 /* Get the Icon from the main app */
464 if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
466 vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
470 /* Fill in the window class structure */
471 wc.style = CS_OWNDC|CS_DBLCLKS; /* style: dbl click */
472 wc.lpfnWndProc = (WNDPROC)DirectXEventProc; /* event handler */
473 wc.cbClsExtra = 0; /* no extra class data */
474 wc.cbWndExtra = 0; /* no extra window data */
475 wc.hInstance = hInstance; /* instance */
476 wc.hIcon = vlc_icon; /* load the vlc big icon */
477 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* default cursor */
478 wc.hbrBackground = GetStockObject(BLACK_BRUSH); /* background color */
479 wc.lpszMenuName = NULL; /* no menu */
480 wc.lpszClassName = _T("VLC DirectX"); /* use a special class */
482 /* Register the window class */
483 if( !RegisterClass(&wc) )
487 if( vlc_icon ) DestroyIcon( vlc_icon );
489 /* Check why it failed. If it's because one already exists
490 * then fine, otherwise return with an error. */
491 if( !GetClassInfo( hInstance, _T("VLC DirectX"), &wndclass ) )
493 msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
498 /* Register the video sub-window class */
499 wc.lpszClassName = _T("VLC DirectX video"); wc.hIcon = 0;
500 wc.hbrBackground = NULL; /* no background color */
501 if( !RegisterClass(&wc) )
505 /* Check why it failed. If it's because one already exists
506 * then fine, otherwise return with an error. */
507 if( !GetClassInfo( hInstance, _T("VLC DirectX video"), &wndclass ) )
509 msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
514 /* When you create a window you give the dimensions you wish it to
515 * have. Unfortunatly these dimensions will include the borders and
516 * titlebar. We use the following function to find out the size of
517 * the window corresponding to the useable surface we want */
518 rect_window.top = 10;
519 rect_window.left = 10;
520 rect_window.right = rect_window.left + p_vout->p_sys->i_window_width;
521 rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
523 if( var_GetBool( p_vout, "video-deco" ) )
525 /* Open with window decoration */
526 AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
527 i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
532 /* No window decoration */
533 AdjustWindowRect( &rect_window, WS_POPUP, 0 );
534 i_style = WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN;
535 i_stylex = 0; // WS_EX_TOOLWINDOW; Is TOOLWINDOW really needed ?
536 // It messes up the fullscreen window.
539 if( p_vout->p_sys->hparent )
541 i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
545 p_vout->p_sys->i_window_style = i_style;
547 /* Create the window */
548 p_vout->p_sys->hwnd =
549 CreateWindowEx( WS_EX_NOPARENTNOTIFY | i_stylex,
550 _T("VLC DirectX"), /* name of window class */
551 _T(VOUT_TITLE) _T(" (DirectX Output)"), /* window title */
552 i_style, /* window style */
553 (p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
554 (UINT)p_vout->p_sys->i_window_x, /* default X coordinate */
555 (p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
556 (UINT)p_vout->p_sys->i_window_y, /* default Y coordinate */
557 rect_window.right - rect_window.left, /* window width */
558 rect_window.bottom - rect_window.top, /* window height */
559 p_vout->p_sys->hparent, /* parent window */
560 NULL, /* no menu in this window */
561 hInstance, /* handle of this program instance */
562 (LPVOID)p_vout ); /* send p_vout to WM_CREATE */
564 if( !p_vout->p_sys->hwnd )
566 msg_Warn( p_vout, "DirectXCreateWindow create window FAILED (err=%lu)", GetLastError() );
570 if( p_vout->p_sys->hparent )
574 /* We don't want the window owner to overwrite our client area */
575 i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
577 if( !(i_style & WS_CLIPCHILDREN) )
578 /* Hmmm, apparently this is a blocking call... */
579 SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
580 i_style | WS_CLIPCHILDREN );
582 /* Create our fullscreen window */
583 p_vout->p_sys->hfswnd =
584 CreateWindowEx( WS_EX_APPWINDOW, _T("VLC DirectX"),
585 _T(VOUT_TITLE) _T(" (DirectX Output)"),
586 WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX,
587 CW_USEDEFAULT, CW_USEDEFAULT,
588 CW_USEDEFAULT, CW_USEDEFAULT,
589 NULL, NULL, hInstance, NULL );
592 /* Append a "Always On Top" entry in the system menu */
593 hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
594 AppendMenu( hMenu, MF_SEPARATOR, 0, _T("") );
595 AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
596 IDM_TOGGLE_ON_TOP, _T("Always on &Top") );
598 /* Create video sub-window. This sub window will always exactly match
599 * the size of the video, which allows us to use crazy overlay colorkeys
600 * without having them shown outside of the video area. */
601 p_vout->p_sys->hvideownd =
602 CreateWindow( _T("VLC DirectX video"), _T(""), /* window class */
603 WS_CHILD, /* window style, not visible initially */
605 p_vout->render.i_width, /* default width */
606 p_vout->render.i_height, /* default height */
607 p_vout->p_sys->hwnd, /* parent window */
609 (LPVOID)p_vout ); /* send p_vout to WM_CREATE */
611 if( !p_vout->p_sys->hvideownd )
612 msg_Warn( p_vout, "can't create video sub-window" );
614 msg_Dbg( p_vout, "created video sub-window" );
616 /* Now display the window */
617 ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
622 /*****************************************************************************
623 * DirectXCloseWindow: close the window created by DirectXCreateWindow
624 *****************************************************************************
625 * This function returns all resources allocated by DirectXCreateWindow.
626 *****************************************************************************/
627 static void DirectXCloseWindow( vout_thread_t *p_vout )
629 msg_Dbg( p_vout, "DirectXCloseWindow" );
631 DestroyWindow( p_vout->p_sys->hwnd );
632 if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
634 #ifdef MODULE_NAME_IS_direct3d
635 if( !p_vout->p_sys->b_desktop )
637 vout_window_Delete( p_vout->p_sys->parent_window );
638 p_vout->p_sys->hwnd = NULL;
640 /* We don't unregister the Window Class because it could lead to race
641 * conditions and it will be done anyway by the system when the app will
645 /*****************************************************************************
646 * DirectXEventProc: This is the window event processing function.
647 *****************************************************************************
648 * On Windows, when you create a window you have to attach an event processing
649 * function to it. The aim of this function is to manage "Queued Messages" and
650 * "Nonqueued Messages".
651 * Queued Messages are those picked up and retransmitted by vout_Manage
652 * (using the GetMessage and DispatchMessage functions).
653 * Nonqueued Messages are those that Windows will send directly to this
654 * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
655 *****************************************************************************/
656 static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
657 WPARAM wParam, LPARAM lParam )
659 vout_thread_t *p_vout;
661 if( message == WM_CREATE )
663 /* Store p_vout for future use */
664 p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
665 SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)p_vout );
670 LONG_PTR p_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA );
671 p_vout = (vout_thread_t *)p_user_data;
674 /* Hmmm mozilla does manage somehow to save the pointer to our
675 * windowproc and still calls it after the vout has been closed. */
676 return DefWindowProc(hwnd, message, wParam, lParam);
681 /* Catch the screensaver and the monitor turn-off */
682 if( message == WM_SYSCOMMAND &&
683 ( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
685 //if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
686 return 0; /* this stops them from happening */
690 if( hwnd == p_vout->p_sys->hvideownd )
694 #ifdef MODULE_NAME_IS_directx
696 /* For overlay, we need to erase background */
697 return !p_vout->p_sys->b_using_overlay ?
698 1 : DefWindowProc(hwnd, message, wParam, lParam);
701 ** For overlay, DefWindowProc() will erase dirty regions
703 ** For non-overlay, vout will paint the whole window at
704 ** regular interval, therefore dirty regions can be ignored
705 ** to minimize repaint.
707 if( !p_vout->p_sys->b_using_overlay )
709 ValidateRect(hwnd, NULL);
711 // fall through to default
714 ** For OpenGL and Direct3D, vout will update the whole
715 ** window at regular interval, therefore dirty region
716 ** can be ignored to minimize repaint.
719 /* nothing to erase */
722 /* nothing to repaint */
723 ValidateRect(hwnd, NULL);
727 return DefWindowProc(hwnd, message, wParam, lParam);
734 case WM_WINDOWPOSCHANGED:
735 UpdateRects( p_vout, true );
738 /* the user wants to close the window */
741 playlist_t * p_playlist = pl_Hold( p_vout );
744 playlist_Stop( p_playlist );
745 pl_Release( p_vout );
750 /* the window has been closed so shut down everything now */
752 msg_Dbg( p_vout, "WinProc WM_DESTROY" );
753 /* just destroy the window */
754 PostQuitMessage( 0 );
760 case IDM_TOGGLE_ON_TOP: /* toggle the "on top" status */
763 msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
765 /* Change the current value */
766 var_Get( p_vout, "video-on-top", &val );
767 val.b_bool = !val.b_bool;
768 var_Set( p_vout, "video-on-top", val );
777 return DefWindowProc(hwnd, message, wParam, lParam);
780 #ifdef MODULE_NAME_IS_wingapi
781 p_vout->p_sys->b_focus = false;
782 if( !p_vout->p_sys->b_parent_focus ) GXSuspend();
785 if( hwnd == p_vout->p_sys->hfswnd )
787 HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
788 ShowWindow( htbar, SW_SHOW );
791 if( !p_vout->p_sys->hparent ||
792 hwnd == p_vout->p_sys->hfswnd )
794 SHFullScreen( hwnd, SHFS_SHOWSIPBUTTON );
800 #ifdef MODULE_NAME_IS_wingapi
801 p_vout->p_sys->b_focus = true;
805 if( p_vout->p_sys->hparent &&
806 hwnd != p_vout->p_sys->hfswnd && p_vout->b_fullscreen )
807 p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
809 if( hwnd == p_vout->p_sys->hfswnd )
811 HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
812 ShowWindow( htbar, SW_HIDE );
815 if( !p_vout->p_sys->hparent ||
816 hwnd == p_vout->p_sys->hfswnd )
818 SHFullScreen( hwnd, SHFS_HIDESIPBUTTON );
824 //msg_Dbg( p_vout, "WinProc WM Default %i", message );
828 /* Let windows handle the message */
829 return DefWindowProc(hwnd, message, wParam, lParam);
837 } dxkeys_to_vlckeys[] =
839 { VK_F1, KEY_F1 }, { VK_F2, KEY_F2 }, { VK_F3, KEY_F3 }, { VK_F4, KEY_F4 },
840 { VK_F5, KEY_F5 }, { VK_F6, KEY_F6 }, { VK_F7, KEY_F7 }, { VK_F8, KEY_F8 },
841 { VK_F9, KEY_F9 }, { VK_F10, KEY_F10 }, { VK_F11, KEY_F11 },
844 { VK_RETURN, KEY_ENTER },
845 { VK_SPACE, KEY_SPACE },
846 { VK_ESCAPE, KEY_ESC },
848 { VK_LEFT, KEY_LEFT },
849 { VK_RIGHT, KEY_RIGHT },
851 { VK_DOWN, KEY_DOWN },
853 { VK_HOME, KEY_HOME },
855 { VK_PRIOR, KEY_PAGEUP },
856 { VK_NEXT, KEY_PAGEDOWN },
858 { VK_INSERT, KEY_INSERT },
859 { VK_DELETE, KEY_DELETE },
865 { VK_BROWSER_BACK, KEY_BROWSER_BACK },
866 { VK_BROWSER_FORWARD, KEY_BROWSER_FORWARD },
867 { VK_BROWSER_REFRESH, KEY_BROWSER_REFRESH },
868 { VK_BROWSER_STOP, KEY_BROWSER_STOP },
869 { VK_BROWSER_SEARCH, KEY_BROWSER_SEARCH },
870 { VK_BROWSER_FAVORITES, KEY_BROWSER_FAVORITES },
871 { VK_BROWSER_HOME, KEY_BROWSER_HOME },
872 { VK_VOLUME_MUTE, KEY_VOLUME_MUTE },
873 { VK_VOLUME_DOWN, KEY_VOLUME_DOWN },
874 { VK_VOLUME_UP, KEY_VOLUME_UP },
875 { VK_MEDIA_NEXT_TRACK, KEY_MEDIA_NEXT_TRACK },
876 { VK_MEDIA_PREV_TRACK, KEY_MEDIA_PREV_TRACK },
877 { VK_MEDIA_STOP, KEY_MEDIA_STOP },
878 { VK_MEDIA_PLAY_PAUSE, KEY_MEDIA_PLAY_PAUSE },
883 static int DirectXConvertKey( int i_key )
887 for( i = 0; dxkeys_to_vlckeys[i].i_dxkey != 0; i++ )
889 if( dxkeys_to_vlckeys[i].i_dxkey == i_key )
891 return dxkeys_to_vlckeys[i].i_vlckey;
898 static event_thread_t *EventThreadCreate( vout_thread_t *p_vout )
900 /* Create the Vout EventThread, this thread is created by us to isolate
901 * the Win32 PeekMessage function calls. We want to do this because
902 * Windows can stay blocked inside this call for a long time, and when
903 * this happens it thus blocks vlc's video_output thread.
904 * Vout EventThread will take care of the creation of the video
905 * window (because PeekMessage has to be called from the same thread which
906 * created the window). */
907 msg_Dbg( p_vout, "creating Vout EventThread" );
908 event_thread_t *p_event = malloc( sizeof(*p_event) );
912 p_event->p_vout = p_vout;
913 vlc_mutex_init( &p_event->lock );
914 vlc_cond_init( &p_event->wait );
919 static void EventThreadDestroy( event_thread_t *p_event )
921 vlc_cond_destroy( &p_event->wait );
922 vlc_mutex_destroy( &p_event->lock );
926 static int EventThreadStart( event_thread_t *p_event )
928 p_event->b_ready = false;
929 p_event->b_done = false;
930 p_event->b_error = false;
932 if( vlc_clone( &p_event->thread, EventThread, p_event,
933 VLC_THREAD_PRIORITY_LOW ) )
935 msg_Err( p_event->p_vout, "cannot create Vout EventThread" );
939 vlc_mutex_lock( &p_event->lock );
940 while( !p_event->b_ready )
941 vlc_cond_wait( &p_event->wait, &p_event->lock );
942 const bool b_error = p_event->b_error;
943 vlc_mutex_unlock( &p_event->lock );
947 vlc_join( p_event->thread, NULL );
948 p_event->b_ready = false;
951 msg_Dbg( p_event->p_vout, "Vout EventThread running" );
955 static void EventThreadStop( event_thread_t *p_event )
957 if( !p_event->b_ready )
960 vlc_mutex_lock( &p_event->lock );
961 p_event->b_done = true;
962 vlc_mutex_unlock( &p_event->lock );
964 /* we need to be sure Vout EventThread won't stay stuck in
965 * GetMessage, so we send a fake message */
966 if( p_event->p_vout->p_sys->hwnd )
967 PostMessage( p_event->p_vout->p_sys->hwnd, WM_NULL, 0, 0);
969 vlc_join( p_event->thread, NULL );
970 p_event->b_ready = false;
972 /* clear the changes formerly signaled */
973 p_event->p_vout->p_sys->i_changes = 0;
977 int CreateEventThread( vout_thread_t *p_vout )
979 event_thread_t *p_event =
980 p_vout->p_sys->p_event = EventThreadCreate( p_vout );
984 if( EventThreadStart( p_event ) )
989 void StopEventThread( vout_thread_t *p_vout )
991 if( p_vout->b_fullscreen )
993 msg_Dbg( p_vout, "Quitting fullscreen" );
994 Win32ToggleFullscreen( p_vout );
995 /* Force fullscreen in the core for the next video */
996 var_SetBool( p_vout, "fullscreen", true );
999 event_thread_t *p_event = p_vout->p_sys->p_event;
1002 EventThreadStop( p_event );
1003 EventThreadDestroy( p_event );
1004 p_vout->p_sys->p_event = NULL;