events.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:33k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * events.c: Windows DirectX video output events handler
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: events.c 9269 2004-11-10 13:04:45Z gbazin $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  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.
  13.  *
  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.
  18.  *
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble: This file contains the functions related to the creation of
  25.  *             a window and the handling of its messages (events).
  26.  *****************************************************************************/
  27. #include <errno.h>                                                 /* ENOMEM */
  28. #include <stdlib.h>                                                /* free() */
  29. #include <ctype.h>                                              /* tolower() */
  30. #include <string.h>                                            /* strerror() */
  31. #ifndef _WIN32_WINNT
  32. #   define _WIN32_WINNT 0x0400
  33. #endif
  34. #include <vlc/vlc.h>
  35. #include <vlc/intf.h>
  36. #include <vlc/input.h>
  37. #include <vlc/vout.h>
  38. #include <windows.h>
  39. #include <windowsx.h>
  40. #include <shellapi.h>
  41. #include <ddraw.h>
  42. #include "vlc_keys.h"
  43. #include "vout.h"
  44. /*****************************************************************************
  45.  * Local prototypes.
  46.  *****************************************************************************/
  47. static int  DirectXCreateWindow( vout_thread_t *p_vout );
  48. static void DirectXCloseWindow ( vout_thread_t *p_vout );
  49. static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
  50. static int Control( vout_thread_t *p_vout, int i_query, va_list args );
  51. static void DirectXPopupMenu( event_thread_t *p_event, vlc_bool_t b_open )
  52. {
  53.     playlist_t *p_playlist =
  54.         vlc_object_find( p_event, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
  55.     if( p_playlist != NULL )
  56.     {
  57.         vlc_value_t val;
  58.         val.b_bool = b_open;
  59.         var_Set( p_playlist, "intf-popupmenu", val );
  60.         vlc_object_release( p_playlist );
  61.     }
  62. }
  63. static int DirectXConvertKey( int i_key );
  64. /*****************************************************************************
  65.  * DirectXEventThread: Create video window & handle its messages
  66.  *****************************************************************************
  67.  * This function creates a video window and then enters an infinite loop
  68.  * that handles the messages sent to that window.
  69.  * The main goal of this thread is to isolate the Win32 PeekMessage function
  70.  * because this one can block for a long time.
  71.  *****************************************************************************/
  72. void DirectXEventThread( event_thread_t *p_event )
  73. {
  74.     MSG msg;
  75.     POINT old_mouse_pos = {0,0}, mouse_pos;
  76.     vlc_value_t val;
  77.     int i_width, i_height, i_x, i_y;
  78.     HMODULE hkernel32;
  79.     /* Initialisation */
  80.     p_event->p_vout->pf_control = Control;
  81.     /* Create a window for the video */
  82.     /* Creating a window under Windows also initializes the thread's event
  83.      * message queue */
  84.     if( DirectXCreateWindow( p_event->p_vout ) )
  85.     {
  86.         msg_Err( p_event, "out of memory" );
  87.         p_event->b_dead = VLC_TRUE;
  88.     }
  89.     /* Signal the creation of the window */
  90.     vlc_thread_ready( p_event );
  91.     /* Set power management stuff */
  92.     if( (hkernel32 = GetModuleHandle( "KERNEL32" ) ) )
  93.     {
  94.         ULONG (WINAPI* OurSetThreadExecutionState)( ULONG );
  95.         OurSetThreadExecutionState =
  96.             GetProcAddress( hkernel32, "SetThreadExecutionState" );
  97.         if( OurSetThreadExecutionState )
  98.             /* Prevent monitor from powering off */
  99.             OurSetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
  100.         else
  101.             msg_Dbg( p_event, "no support for SetThreadExecutionState()" );
  102.     }
  103.     /* Main loop */
  104.     /* GetMessage will sleep if there's no message in the queue */
  105.     while( !p_event->b_die && GetMessage( &msg, 0, 0, 0 ) )
  106.     {
  107.         /* Check if we are asked to exit */
  108.         if( p_event->b_die )
  109.             break;
  110.         switch( msg.message )
  111.         {
  112.         case WM_MOUSEMOVE:
  113.             vout_PlacePicture( p_event->p_vout,
  114.                                p_event->p_vout->p_sys->i_window_width,
  115.                                p_event->p_vout->p_sys->i_window_height,
  116.                                &i_x, &i_y, &i_width, &i_height );
  117.             if( msg.hwnd == p_event->p_vout->p_sys->hvideownd )
  118.             {
  119.                 /* Child window */
  120.                 i_x = i_y = 0;
  121.             }
  122.             if( i_width && i_height )
  123.             {
  124.                 val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x )
  125.                              * p_event->p_vout->render.i_width / i_width;
  126.                 var_Set( p_event->p_vout, "mouse-x", val );
  127.                 val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y )
  128.                              * p_event->p_vout->render.i_height / i_height;
  129.                 var_Set( p_event->p_vout, "mouse-y", val );
  130.                 val.b_bool = VLC_TRUE;
  131.                 var_Set( p_event->p_vout, "mouse-moved", val );
  132.             }
  133.         case WM_NCMOUSEMOVE:
  134.             GetCursorPos( &mouse_pos );
  135.             if( (abs(mouse_pos.x - old_mouse_pos.x) > 2 ||
  136.                 (abs(mouse_pos.y - old_mouse_pos.y)) > 2 ) )
  137.             {
  138.                 GetCursorPos( &old_mouse_pos );
  139.                 p_event->p_vout->p_sys->i_lastmoved = mdate();
  140.                 if( p_event->p_vout->p_sys->b_cursor_hidden )
  141.                 {
  142.                     p_event->p_vout->p_sys->b_cursor_hidden = 0;
  143.                     ShowCursor( TRUE );
  144.                 }
  145.             }
  146.             break;
  147.         case WM_VLC_HIDE_MOUSE:
  148.             if( p_event->p_vout->p_sys->b_cursor_hidden ) break;
  149.             p_event->p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
  150.             GetCursorPos( &old_mouse_pos );
  151.             ShowCursor( FALSE );
  152.             break;
  153.         case WM_VLC_SHOW_MOUSE:
  154.             if( !p_event->p_vout->p_sys->b_cursor_hidden ) break;
  155.             p_event->p_vout->p_sys->b_cursor_hidden = VLC_FALSE;
  156.             GetCursorPos( &old_mouse_pos );
  157.             ShowCursor( TRUE );
  158.             break;
  159.         case WM_LBUTTONDOWN:
  160.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  161.             val.i_int |= 1;
  162.             var_Set( p_event->p_vout, "mouse-button-down", val );
  163.             DirectXPopupMenu( p_event, VLC_FALSE );
  164.             break;
  165.         case WM_LBUTTONUP:
  166.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  167.             val.i_int &= ~1;
  168.             var_Set( p_event->p_vout, "mouse-button-down", val );
  169.             val.b_bool = VLC_TRUE;
  170.             var_Set( p_event->p_vout, "mouse-clicked", val );
  171.             break;
  172.         case WM_LBUTTONDBLCLK:
  173.             p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
  174.             break;
  175.         case WM_MBUTTONDOWN:
  176.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  177.             val.i_int |= 2;
  178.             var_Set( p_event->p_vout, "mouse-button-down", val );
  179.             DirectXPopupMenu( p_event, VLC_FALSE );
  180.             break;
  181.         case WM_MBUTTONUP:
  182.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  183.             val.i_int &= ~2;
  184.             var_Set( p_event->p_vout, "mouse-button-down", val );
  185.             break;
  186.         case WM_RBUTTONDOWN:
  187.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  188.             val.i_int |= 4;
  189.             var_Set( p_event->p_vout, "mouse-button-down", val );
  190.             DirectXPopupMenu( p_event, VLC_FALSE );
  191.             break;
  192.         case WM_RBUTTONUP:
  193.             var_Get( p_event->p_vout, "mouse-button-down", &val );
  194.             val.i_int &= ~4;
  195.             var_Set( p_event->p_vout, "mouse-button-down", val );
  196.             DirectXPopupMenu( p_event, VLC_TRUE );
  197.             break;
  198.         case WM_KEYDOWN:
  199.         case WM_SYSKEYDOWN:
  200.             /* The key events are first processed here and not translated
  201.              * into WM_CHAR events because we need to know the status of the
  202.              * modifier keys. */
  203.             val.i_int = DirectXConvertKey( msg.wParam );
  204.             if( !val.i_int )
  205.             {
  206.                 /* This appears to be a "normal" (ascii) key */
  207.                 val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) );
  208.             }
  209.             if( val.i_int )
  210.             {
  211.                 if( GetKeyState(VK_CONTROL) & 0x8000 )
  212.                 {
  213.                     val.i_int |= KEY_MODIFIER_CTRL;
  214.                 }
  215.                 if( GetKeyState(VK_SHIFT) & 0x8000 )
  216.                 {
  217.                     val.i_int |= KEY_MODIFIER_SHIFT;
  218.                 }
  219.                 if( GetKeyState(VK_MENU) & 0x8000 )
  220.                 {
  221.                     val.i_int |= KEY_MODIFIER_ALT;
  222.                 }
  223.                 var_Set( p_event->p_vlc, "key-pressed", val );
  224.             }
  225.             break;
  226.         case WM_MOUSEWHEEL:
  227.             if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 )
  228.             {
  229.                 val.i_int = KEY_MOUSEWHEELUP;
  230.             }
  231.             else
  232.             {
  233.                 val.i_int = KEY_MOUSEWHEELDOWN;
  234.             }
  235.             if( val.i_int )
  236.             {
  237.                 if( GetKeyState(VK_CONTROL) & 0x8000 )
  238.                 {
  239.                     val.i_int |= KEY_MODIFIER_CTRL;
  240.                 }
  241.                 if( GetKeyState(VK_SHIFT) & 0x8000 )
  242.                 {
  243.                     val.i_int |= KEY_MODIFIER_SHIFT;
  244.                 }
  245.                 if( GetKeyState(VK_MENU) & 0x8000 )
  246.                 {
  247.                     val.i_int |= KEY_MODIFIER_ALT;
  248.                 }
  249.                 var_Set( p_event->p_vlc, "key-pressed", val );
  250.             }
  251.             break;
  252.         case WM_VLC_CHANGE_TEXT:
  253.             var_Get( p_event->p_vout, "video-title", &val );
  254.             if( !val.psz_string || !*val.psz_string ) /* Default video title */
  255.             {
  256. #ifdef MODULE_NAME_IS_glwin32
  257.                 SetWindowText( p_event->p_vout->p_sys->hwnd,
  258.                     VOUT_TITLE " (OpenGL output)" );
  259. #else
  260.                 if( p_event->p_vout->p_sys->b_using_overlay )
  261.                     SetWindowText( p_event->p_vout->p_sys->hwnd,
  262.                         VOUT_TITLE " (hardware YUV overlay DirectX output)" );
  263.                 else if( p_event->p_vout->p_sys->b_hw_yuv )
  264.                     SetWindowText( p_event->p_vout->p_sys->hwnd,
  265.                         VOUT_TITLE " (hardware YUV DirectX output)" );
  266.                 else SetWindowText( p_event->p_vout->p_sys->hwnd,
  267.                         VOUT_TITLE " (software RGB DirectX output)" );
  268. #endif
  269.             }
  270.             else
  271.             {
  272.                 SetWindowText( p_event->p_vout->p_sys->hwnd, val.psz_string );
  273.             }
  274.             break;
  275.         default:
  276.             /* Messages we don't handle directly are dispatched to the
  277.              * window procedure */
  278.             TranslateMessage(&msg);
  279.             DispatchMessage(&msg);
  280.             break;
  281.         } /* End Switch */
  282.     } /* End Main loop */
  283.     /* Check for WM_QUIT if we created the window */
  284.     if( !p_event->p_vout->p_sys->hparent && msg.message == WM_QUIT )
  285.     {
  286.         msg_Warn( p_event, "WM_QUIT... should not happen!!" );
  287.         p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
  288.     }
  289.     msg_Dbg( p_event, "DirectXEventThread terminating" );
  290.     /* clear the changes formerly signaled */
  291.     p_event->p_vout->p_sys->i_changes = 0;
  292.     DirectXCloseWindow( p_event->p_vout );
  293. }
  294. /* following functions are local */
  295. /*****************************************************************************
  296.  * DirectXCreateWindow: create a window for the video.
  297.  *****************************************************************************
  298.  * Before creating a direct draw surface, we need to create a window in which
  299.  * the video will be displayed. This window will also allow us to capture the
  300.  * events.
  301.  *****************************************************************************/
  302. static int DirectXCreateWindow( vout_thread_t *p_vout )
  303. {
  304.     HINSTANCE  hInstance;
  305.     HMENU      hMenu;
  306.     RECT       rect_window;
  307.     WNDCLASSEX wc;                            /* window class components */
  308.     HICON      vlc_icon = NULL;
  309.     char       vlc_path[MAX_PATH+1];
  310.     int        i_style;
  311.     msg_Dbg( p_vout, "DirectXCreateWindow" );
  312.     /* Get this module's instance */
  313.     hInstance = GetModuleHandle(NULL);
  314.     /* If an external window was specified, we'll draw in it. */
  315.     p_vout->p_sys->hparent =
  316.         vout_RequestWindow( p_vout, &p_vout->p_sys->i_window_x,
  317.                             &p_vout->p_sys->i_window_y,
  318.                             &p_vout->p_sys->i_window_width,
  319.                             &p_vout->p_sys->i_window_height );
  320.     /* We create the window ourself, there is no previous window proc. */
  321.     p_vout->p_sys->pf_wndproc = NULL;
  322.     /* Get the Icon from the main app */
  323.     vlc_icon = NULL;
  324.     if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
  325.     {
  326.         vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
  327.     }
  328.     /* Fill in the window class structure */
  329.     wc.cbSize        = sizeof(WNDCLASSEX);
  330.     wc.style         = CS_OWNDC|CS_DBLCLKS;          /* style: dbl click */
  331.     wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;       /* event handler */
  332.     wc.cbClsExtra    = 0;                         /* no extra class data */
  333.     wc.cbWndExtra    = 0;                        /* no extra window data */
  334.     wc.hInstance     = hInstance;                            /* instance */
  335.     wc.hIcon         = vlc_icon;                /* load the vlc big icon */
  336.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    /* default cursor */
  337.     wc.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
  338.     wc.lpszMenuName  = NULL;                                  /* no menu */
  339.     wc.lpszClassName = "VLC DirectX";             /* use a special class */
  340.     wc.hIconSm       = vlc_icon;              /* load the vlc small icon */
  341.     /* Register the window class */
  342.     if( !RegisterClassEx(&wc) )
  343.     {
  344.         WNDCLASS wndclass;
  345.         if( vlc_icon ) DestroyIcon( vlc_icon );
  346.         /* Check why it failed. If it's because one already exists
  347.          * then fine, otherwise return with an error. */
  348.         if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
  349.         {
  350.             msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
  351.             return VLC_EGENERIC;
  352.         }
  353.     }
  354.     /* Register the video sub-window class */
  355.     wc.lpszClassName = "VLC DirectX video"; wc.hIconSm = 0; wc.hIcon = 0;
  356.     if( !RegisterClassEx(&wc) )
  357.     {
  358.         WNDCLASS wndclass;
  359.         /* Check why it failed. If it's because one already exists
  360.          * then fine, otherwise return with an error. */
  361.         if( !GetClassInfo( hInstance, "VLC DirectX video", &wndclass ) )
  362.         {
  363.             msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
  364.             return VLC_EGENERIC;
  365.         }
  366.     }
  367.     /* When you create a window you give the dimensions you wish it to
  368.      * have. Unfortunatly these dimensions will include the borders and
  369.      * titlebar. We use the following function to find out the size of
  370.      * the window corresponding to the useable surface we want */
  371.     rect_window.top    = 10;
  372.     rect_window.left   = 10;
  373.     rect_window.right  = rect_window.left + p_vout->p_sys->i_window_width;
  374.     rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
  375.     AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
  376.     i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
  377.     if( p_vout->p_sys->hparent )
  378.     {
  379.         i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
  380.     }
  381.     /* Create the window */
  382.     p_vout->p_sys->hwnd =
  383.         CreateWindowEx( WS_EX_NOPARENTNOTIFY,
  384.                     "VLC DirectX",                   /* name of window class */
  385.                     VOUT_TITLE " (DirectX Output)", /* window title bar text */
  386.                     i_style,                                 /* window style */
  387.                     (p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
  388.                         p_vout->p_sys->i_window_x,   /* default X coordinate */
  389.                     (p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
  390.                         p_vout->p_sys->i_window_y,   /* default Y coordinate */
  391.                     rect_window.right - rect_window.left,    /* window width */
  392.                     rect_window.bottom - rect_window.top,   /* window height */
  393.                     p_vout->p_sys->hparent,                 /* parent window */
  394.                     NULL,                          /* no menu in this window */
  395.                     hInstance,            /* handle of this program instance */
  396.                     (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
  397.     if( !p_vout->p_sys->hwnd )
  398.     {
  399.         msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
  400.         return VLC_EGENERIC;
  401.     }
  402.     if( p_vout->p_sys->hparent )
  403.     {
  404.         LONG i_style;
  405.         /* We don't want the window owner to overwrite our client area */
  406.         i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
  407.         if( !(i_style & WS_CLIPCHILDREN) )
  408.             /* Hmmm, apparently this is a blocking call... */
  409.             SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
  410.                            i_style | WS_CLIPCHILDREN );
  411.         /* Create our fullscreen window */
  412.         p_vout->p_sys->hfswnd =
  413.             CreateWindowEx( WS_EX_APPWINDOW, "VLC DirectX",
  414.                             VOUT_TITLE " (DirectX Output)",
  415.                             WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX,
  416.                             CW_USEDEFAULT, CW_USEDEFAULT,
  417.                             CW_USEDEFAULT, CW_USEDEFAULT,
  418.                             NULL, NULL, hInstance, NULL );
  419.     }
  420.     /* Now display the window */
  421.     ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
  422.     /* Create video sub-window. This sub window will always exactly match
  423.      * the size of the video, which allows us to use crazy overlay colorkeys
  424.      * without having them shown outside of the video area. */
  425.     SendMessage( p_vout->p_sys->hwnd, WM_VLC_CREATE_VIDEO_WIN, 0, 0 );
  426.     /* Append a "Always On Top" entry in the system menu */
  427.     hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
  428.     AppendMenu( hMenu, MF_SEPARATOR, 0, "" );
  429.     AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
  430.                        IDM_TOGGLE_ON_TOP, "Always on &Top" );
  431.     return VLC_SUCCESS;
  432. }
  433. /*****************************************************************************
  434.  * DirectXCloseWindow: close the window created by DirectXCreateWindow
  435.  *****************************************************************************
  436.  * This function returns all resources allocated by DirectXCreateWindow.
  437.  *****************************************************************************/
  438. static void DirectXCloseWindow( vout_thread_t *p_vout )
  439. {
  440.     msg_Dbg( p_vout, "DirectXCloseWindow" );
  441.     DestroyWindow( p_vout->p_sys->hwnd );
  442.     if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
  443.     if( p_vout->p_sys->hparent )
  444.         vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
  445.     p_vout->p_sys->hwnd = NULL;
  446.     /* We don't unregister the Window Class because it could lead to race
  447.      * conditions and it will be done anyway by the system when the app will
  448.      * exit */
  449. }
  450. /*****************************************************************************
  451.  * DirectXUpdateRects: update clipping rectangles
  452.  *****************************************************************************
  453.  * This function is called when the window position or size are changed, and
  454.  * its job is to update the source and destination RECTs used to display the
  455.  * picture.
  456.  *****************************************************************************/
  457. void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
  458. {
  459. #define rect_src p_vout->p_sys->rect_src
  460. #define rect_src_clipped p_vout->p_sys->rect_src_clipped
  461. #define rect_dest p_vout->p_sys->rect_dest
  462. #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
  463.     int i_width, i_height, i_x, i_y;
  464.     RECT  rect;
  465.     POINT point;
  466.     /* Retrieve the window size */
  467.     GetClientRect( p_vout->p_sys->hwnd, &rect );
  468.     /* Retrieve the window position */
  469.     point.x = point.y = 0;
  470.     ClientToScreen( p_vout->p_sys->hwnd, &point );
  471.     /* If nothing changed, we can return */
  472.     if( !b_force
  473.          && p_vout->p_sys->i_window_width == rect.right
  474.          && p_vout->p_sys->i_window_height == rect.bottom
  475.          && p_vout->p_sys->i_window_x == point.x
  476.          && p_vout->p_sys->i_window_y == point.y )
  477.     {
  478.         return;
  479.     }
  480.     /* Update the window position and size */
  481.     p_vout->p_sys->i_window_x = point.x;
  482.     p_vout->p_sys->i_window_y = point.y;
  483.     p_vout->p_sys->i_window_width = rect.right;
  484.     p_vout->p_sys->i_window_height = rect.bottom;
  485.     vout_PlacePicture( p_vout, rect.right, rect.bottom,
  486.                        &i_x, &i_y, &i_width, &i_height );
  487.     if( p_vout->p_sys->hvideownd )
  488.         SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
  489.                       i_x, i_y, i_width, i_height, 0 );
  490.     /* Destination image position and dimensions */
  491.     rect_dest.left = point.x + i_x;
  492.     rect_dest.right = rect_dest.left + i_width;
  493.     rect_dest.top = point.y + i_y;
  494.     rect_dest.bottom = rect_dest.top + i_height;
  495.     /* Apply overlay hardware constraints */
  496.     if( p_vout->p_sys->b_using_overlay )
  497.     {
  498.         if( p_vout->p_sys->i_align_dest_boundary )
  499.             rect_dest.left = ( rect_dest.left +
  500.                 p_vout->p_sys->i_align_dest_boundary / 2 ) & 
  501.                 ~p_vout->p_sys->i_align_dest_boundary;
  502.         if( p_vout->p_sys->i_align_dest_size )
  503.             rect_dest.right = (( rect_dest.right - rect_dest.left +
  504.                 p_vout->p_sys->i_align_dest_size / 2 ) & 
  505.                 ~p_vout->p_sys->i_align_dest_size) + rect_dest.left;
  506.     }
  507.     /* UpdateOverlay directdraw function doesn't automatically clip to the
  508.      * display size so we need to do it otherwise it will fail */
  509.     /* Clip the destination window */
  510.     if( !IntersectRect( &rect_dest_clipped, &rect_dest,
  511.                         &p_vout->p_sys->rect_display ) )
  512.     {
  513.         SetRectEmpty( &rect_src_clipped );
  514.         return;
  515.     }
  516. #if 0
  517.     msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
  518.                      " %i,%i,%i,%i",
  519.                      rect_dest_clipped.left, rect_dest_clipped.top,
  520.                      rect_dest_clipped.right, rect_dest_clipped.bottom );
  521. #endif
  522.     /* the 2 following lines are to fix a bug when clicking on the desktop */
  523.     if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
  524.         (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
  525.     {
  526.         SetRectEmpty( &rect_src_clipped );
  527.         return;
  528.     }
  529.     /* src image dimensions */
  530.     rect_src.left = 0;
  531.     rect_src.top = 0;
  532.     rect_src.right = p_vout->render.i_width;
  533.     rect_src.bottom = p_vout->render.i_height;
  534.     /* Clip the source image */
  535.     rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
  536.       p_vout->render.i_width / (rect_dest.right - rect_dest.left);
  537.     rect_src_clipped.right = p_vout->render.i_width -
  538.       (rect_dest.right - rect_dest_clipped.right) * p_vout->render.i_width /
  539.       (rect_dest.right - rect_dest.left);
  540.     rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
  541.       p_vout->render.i_height / (rect_dest.bottom - rect_dest.top);
  542.     rect_src_clipped.bottom = p_vout->render.i_height -
  543.       (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->render.i_height /
  544.       (rect_dest.bottom - rect_dest.top);
  545.     /* Apply overlay hardware constraints */
  546.     if( p_vout->p_sys->b_using_overlay )
  547.     {
  548.         if( p_vout->p_sys->i_align_src_boundary )
  549.             rect_src_clipped.left = ( rect_src_clipped.left +
  550.                 p_vout->p_sys->i_align_src_boundary / 2 ) & 
  551.                 ~p_vout->p_sys->i_align_src_boundary;
  552.         if( p_vout->p_sys->i_align_src_size )
  553.             rect_src_clipped.right = (( rect_src_clipped.right -
  554.                 rect_src_clipped.left +
  555.                 p_vout->p_sys->i_align_src_size / 2 ) & 
  556.                 ~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left;
  557.     }
  558. #if 0
  559.     msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
  560.                      " coords: %i,%i,%i,%i",
  561.                      rect_src_clipped.left, rect_src_clipped.top,
  562.                      rect_src_clipped.right, rect_src_clipped.bottom );
  563. #endif
  564.     /* The destination coordinates need to be relative to the current
  565.      * directdraw primary surface (display) */
  566.     rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
  567.     rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
  568.     rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
  569.     rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
  570.     if( p_vout->p_sys->b_using_overlay )
  571.         DirectXUpdateOverlay( p_vout );
  572.     /* Signal the change in size/position */
  573.     p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
  574. #undef rect_src
  575. #undef rect_src_clipped
  576. #undef rect_dest
  577. #undef rect_dest_clipped
  578. }
  579. /*****************************************************************************
  580.  * DirectXEventProc: This is the window event processing function.
  581.  *****************************************************************************
  582.  * On Windows, when you create a window you have to attach an event processing
  583.  * function to it. The aim of this function is to manage "Queued Messages" and
  584.  * "Nonqueued Messages".
  585.  * Queued Messages are those picked up and retransmitted by vout_Manage
  586.  * (using the GetMessage and DispatchMessage functions).
  587.  * Nonqueued Messages are those that Windows will send directly to this
  588.  * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
  589.  *****************************************************************************/
  590. static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
  591.                                          WPARAM wParam, LPARAM lParam )
  592. {
  593.     vout_thread_t *p_vout;
  594.     if( message == WM_CREATE )
  595.     {
  596.         /* Store p_vout for future use */
  597.         p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
  598.         SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)p_vout );
  599.     }
  600.     else
  601.     {
  602.         p_vout = (vout_thread_t *)GetWindowLongPtr( hwnd, GWLP_USERDATA );
  603.     }
  604.     if( !p_vout )
  605.     {
  606.         /* Hmmm mozilla does manage somehow to save the pointer to our
  607.          * windowproc and still calls it after the vout has been closed. */
  608.         return DefWindowProc(hwnd, message, wParam, lParam);
  609.     }
  610.     if( hwnd == p_vout->p_sys->hvideownd )
  611.         return DefWindowProc(hwnd, message, wParam, lParam);
  612.     switch( message )
  613.     {
  614.     case WM_WINDOWPOSCHANGED:
  615.         DirectXUpdateRects( p_vout, VLC_TRUE );
  616.         return 0;
  617.     /* the user wants to close the window */
  618.     case WM_CLOSE:
  619.     {
  620.         playlist_t * p_playlist =
  621.             (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
  622.                                            FIND_ANYWHERE );
  623.         if( p_playlist == NULL )
  624.         {
  625.             return 0;
  626.         }
  627.         playlist_Stop( p_playlist );
  628.         vlc_object_release( p_playlist );
  629.         return 0;
  630.     }
  631.     /* the window has been closed so shut down everything now */
  632.     case WM_DESTROY:
  633.         msg_Dbg( p_vout, "WinProc WM_DESTROY" );
  634.         /* just destroy the window */
  635.         PostQuitMessage( 0 );
  636.         return 0;
  637.     case WM_SYSCOMMAND:
  638.         switch (wParam)
  639.         {
  640.             case SC_SCREENSAVE:                     /* catch the screensaver */
  641.             case SC_MONITORPOWER:              /* catch the monitor turn-off */
  642.                 msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" );
  643.                 return 0;                  /* this stops them from happening */
  644.             case IDM_TOGGLE_ON_TOP:            /* toggle the "on top" status */
  645.             {
  646.                 vlc_value_t val;
  647.                 msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
  648.                 /* Get the current value... */
  649.                 if( var_Get( p_vout, "video-on-top", &val ) < 0 )
  650.                     return 0;
  651.                 /* ...and change it */
  652.                 val.b_bool = !val.b_bool;
  653.                 var_Set( p_vout, "video-on-top", val );
  654.                 return 0;
  655.                 break;
  656.             }
  657.         }
  658.         break;
  659.     case WM_VLC_CREATE_VIDEO_WIN:
  660.         /* Create video sub-window */
  661.         p_vout->p_sys->hvideownd =
  662.             CreateWindow( "VLC DirectX video", "",      /* window class text */
  663.                     WS_CHILD | WS_VISIBLE,                   /* window style */
  664.                     CW_USEDEFAULT, CW_USEDEFAULT,     /* default coordinates */
  665.                     CW_USEDEFAULT, CW_USEDEFAULT,
  666.                     hwnd,                                   /* parent window */
  667.                     NULL, GetModuleHandle(NULL),
  668.                     (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
  669.         if( !p_vout->p_sys->hvideownd )
  670.             msg_Warn( p_vout, "Can't create video sub-window" );
  671.         else
  672.             msg_Dbg( p_vout, "Created video sub-window" );
  673.         break;
  674.     case WM_PAINT:
  675.     case WM_NCPAINT:
  676.     case WM_ERASEBKGND:
  677.         /* We do not want to relay these messages to the parent window
  678.          * because we rely on the background color for the overlay. */
  679.         return DefWindowProc(hwnd, message, wParam, lParam);
  680.         break;
  681.     default:
  682.         //msg_Dbg( p_vout, "WinProc WM Default %i", message );
  683.         break;
  684.     }
  685.     /* Let windows handle the message */
  686.     return DefWindowProc(hwnd, message, wParam, lParam);
  687. }
  688. static struct
  689. {
  690.     int i_dxkey;
  691.     int i_vlckey;
  692. } dxkeys_to_vlckeys[] =
  693. {
  694.     { VK_F1, KEY_F1 }, { VK_F2, KEY_F2 }, { VK_F3, KEY_F3 }, { VK_F4, KEY_F4 },
  695.     { VK_F5, KEY_F5 }, { VK_F6, KEY_F6 }, { VK_F7, KEY_F7 }, { VK_F8, KEY_F8 },
  696.     { VK_F9, KEY_F9 }, { VK_F10, KEY_F10 }, { VK_F11, KEY_F11 },
  697.     { VK_F12, KEY_F12 },
  698.     { VK_RETURN, KEY_ENTER },
  699.     { VK_SPACE, KEY_SPACE },
  700.     { VK_ESCAPE, KEY_ESC },
  701.     { VK_LEFT, KEY_LEFT },
  702.     { VK_RIGHT, KEY_RIGHT },
  703.     { VK_UP, KEY_UP },
  704.     { VK_DOWN, KEY_DOWN },
  705.     { VK_HOME, KEY_HOME },
  706.     { VK_END, KEY_END },
  707.     { VK_PRIOR, KEY_PAGEUP },
  708.     { VK_NEXT, KEY_PAGEDOWN },
  709.     { VK_CONTROL, 0 },
  710.     { VK_SHIFT, 0 },
  711.     { VK_MENU, 0 },
  712.     { 0, 0 }
  713. };
  714. static int DirectXConvertKey( int i_key )
  715. {
  716.     int i;
  717.     for( i = 0; dxkeys_to_vlckeys[i].i_dxkey != 0; i++ )
  718.     {
  719.         if( dxkeys_to_vlckeys[i].i_dxkey == i_key )
  720.         {
  721.             return dxkeys_to_vlckeys[i].i_vlckey;
  722.         }
  723.     }
  724.     return 0;
  725. }
  726. /*****************************************************************************
  727.  * Control: control facility for the vout
  728.  *****************************************************************************/
  729. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  730. {
  731.     double f_arg;
  732.     RECT rect_window;
  733.     POINT point;
  734.     switch( i_query )
  735.     {
  736.     case VOUT_SET_ZOOM:
  737.         if( p_vout->p_sys->hparent )
  738.             return vout_ControlWindow( p_vout,
  739.                     (void *)p_vout->p_sys->hparent, i_query, args );
  740.         f_arg = va_arg( args, double );
  741.         /* Update dimensions */
  742.         rect_window.top = rect_window.left = 0;
  743.         rect_window.right  = p_vout->i_window_width * f_arg;
  744.         rect_window.bottom = p_vout->i_window_height * f_arg;
  745.         AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
  746.         SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  747.                       rect_window.right - rect_window.left,
  748.                       rect_window.bottom - rect_window.top, SWP_NOMOVE );
  749.         return VLC_SUCCESS;
  750.     case VOUT_CLOSE:
  751.         ShowWindow( p_vout->p_sys->hwnd, SW_HIDE );
  752.     case VOUT_REPARENT:
  753.         /* Change window style, borders and title bar */
  754.         vlc_mutex_lock( &p_vout->p_sys->lock );
  755.         p_vout->p_sys->hparent = 0;
  756.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  757.         /* Retrieve the window position */
  758.         point.x = point.y = 0;
  759.         ClientToScreen( p_vout->p_sys->hwnd, &point );
  760.         SetParent( p_vout->p_sys->hwnd, GetDesktopWindow() );
  761.         SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
  762.                        WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
  763.                        WS_SIZEBOX | (i_query == VOUT_CLOSE ? 0 : WS_VISIBLE) );
  764.         SetWindowPos( p_vout->p_sys->hwnd, 0, point.x, point.y, 0, 0,
  765.                       SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
  766.         return vout_vaControlDefault( p_vout, i_query, args );
  767.     case VOUT_SET_STAY_ON_TOP:
  768.         if( p_vout->p_sys->hparent )
  769.             return vout_ControlWindow( p_vout,
  770.                     (void *)p_vout->p_sys->hparent, i_query, args );
  771.         p_vout->p_sys->b_on_top_change = VLC_TRUE;
  772.         return VLC_SUCCESS;
  773.     default:
  774.         return vout_vaControlDefault( p_vout, i_query, args );
  775.     }
  776. }