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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * glwin32.c: Windows OpenGL provider
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: glwin32.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. #include <errno.h>                                                 /* ENOMEM */
  24. #include <stdlib.h>                                                /* free() */
  25. #include <string.h>                                            /* strerror() */
  26. #include <vlc/vlc.h>
  27. #include <vlc/intf.h>
  28. #include <vlc/vout.h>
  29. #include <windows.h>
  30. #include <ddraw.h>
  31. #include <commctrl.h>
  32. #include <multimon.h>
  33. #undef GetSystemMetrics
  34. #ifndef MONITOR_DEFAULTTONEAREST
  35. #   define MONITOR_DEFAULTTONEAREST 2
  36. #endif
  37. #include <GL/gl.h>
  38. #include "vout.h"
  39. /*****************************************************************************
  40.  * Local prototypes.
  41.  *****************************************************************************/
  42. static int  OpenVideo  ( vlc_object_t * );
  43. static void CloseVideo ( vlc_object_t * );
  44. static int  Init      ( vout_thread_t * );
  45. static void End       ( vout_thread_t * );
  46. static int  Manage    ( vout_thread_t * );
  47. static void GLSwapBuffers( vout_thread_t * );
  48. /*****************************************************************************
  49.  * Module descriptor
  50.  *****************************************************************************/
  51. vlc_module_begin();
  52.     set_description( _("Win32 OpenGL provider") );
  53.     set_capability( "opengl provider", 100 );
  54.     add_shortcut( "glwin32" );
  55.     set_callbacks( OpenVideo, CloseVideo );
  56. vlc_module_end();
  57. #if 0 /* FIXME */
  58.     /* check if we registered a window class because we need to
  59.      * unregister it */
  60.     WNDCLASS wndclass;
  61.     if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
  62.         UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
  63. #endif
  64. /*****************************************************************************
  65.  * OpenVideo: allocate OpenGL provider
  66.  *****************************************************************************
  67.  * This function creates and initializes a video window.
  68.  *****************************************************************************/
  69. static int OpenVideo( vlc_object_t *p_this )
  70. {
  71.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  72.     vlc_value_t val;
  73.     /* Allocate structure */
  74.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  75.     if( p_vout->p_sys == NULL )
  76.     {
  77.         msg_Err( p_vout, "out of memory" );
  78.         return VLC_ENOMEM;
  79.     }
  80.     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
  81.     /* Initialisations */
  82.     p_vout->pf_init = Init;
  83.     p_vout->pf_end = End;
  84.     p_vout->pf_manage = Manage;
  85.     p_vout->pf_swap = GLSwapBuffers;
  86.     p_vout->p_sys->p_ddobject = NULL;
  87.     p_vout->p_sys->p_display = NULL;
  88.     p_vout->p_sys->p_current_surface = NULL;
  89.     p_vout->p_sys->p_clipper = NULL;
  90.     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
  91.     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
  92.     p_vout->p_sys->i_changes = 0;
  93.     p_vout->p_sys->b_wallpaper = 0;
  94.     vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
  95.     SetRectEmpty( &p_vout->p_sys->rect_display );
  96.     SetRectEmpty( &p_vout->p_sys->rect_parent );
  97.     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  98.     p_vout->p_sys->b_cursor_hidden = 0;
  99.     p_vout->p_sys->i_lastmoved = mdate();
  100.     /* Set main window's size */
  101.     p_vout->p_sys->i_window_width = p_vout->i_window_width;
  102.     p_vout->p_sys->i_window_height = p_vout->i_window_height;
  103.     /* Create the DirectXEventThread, this thread is created by us to isolate
  104.      * the Win32 PeekMessage function calls. We want to do this because
  105.      * Windows can stay blocked inside this call for a long time, and when
  106.      * this happens it thus blocks vlc's video_output thread.
  107.      * DirectXEventThread will take care of the creation of the video
  108.      * window (because PeekMessage has to be called from the same thread which
  109.      * created the window). */
  110.     msg_Dbg( p_vout, "creating DirectXEventThread" );
  111.     p_vout->p_sys->p_event =
  112.         vlc_object_create( p_vout, sizeof(event_thread_t) );
  113.     p_vout->p_sys->p_event->p_vout = p_vout;
  114.     if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
  115.                            DirectXEventThread, 0, 1 ) )
  116.     {
  117.         msg_Err( p_vout, "cannot create DirectXEventThread" );
  118.         vlc_object_destroy( p_vout->p_sys->p_event );
  119.         p_vout->p_sys->p_event = NULL;
  120.         goto error;
  121.     }
  122.     if( p_vout->p_sys->p_event->b_error )
  123.     {
  124.         msg_Err( p_vout, "DirectXEventThread failed" );
  125.         goto error;
  126.     }
  127.     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
  128.     msg_Dbg( p_vout, "DirectXEventThread running" );
  129.     /* Variable to indicate if the window should be on top of others */
  130.     /* Trigger a callback right now */
  131.     var_Get( p_vout, "video-on-top", &val );
  132.     var_Set( p_vout, "video-on-top", val );
  133.     return VLC_SUCCESS;
  134.  error:
  135.     CloseVideo( VLC_OBJECT(p_vout) );
  136.     return VLC_EGENERIC;
  137. }
  138. /*****************************************************************************
  139.  * Init: initialize video thread output method
  140.  *****************************************************************************/
  141. static int Init( vout_thread_t *p_vout )
  142. {
  143.     PIXELFORMATDESCRIPTOR pfd;
  144.     int iFormat;
  145.     /* Change the window title bar text */
  146.     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
  147.     p_vout->p_sys->hGLDC = GetDC( p_vout->p_sys->hvideownd );
  148.     /* Set the pixel format for the DC */
  149.     memset( &pfd, 0, sizeof( pfd ) );
  150.     pfd.nSize = sizeof( pfd );
  151.     pfd.nVersion = 1;
  152.     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  153.     pfd.iPixelType = PFD_TYPE_RGBA;
  154.     pfd.cColorBits = 24;
  155.     pfd.cDepthBits = 16;
  156.     pfd.iLayerType = PFD_MAIN_PLANE;
  157.     iFormat = ChoosePixelFormat( p_vout->p_sys->hGLDC, &pfd );
  158.     SetPixelFormat( p_vout->p_sys->hGLDC, iFormat, &pfd );
  159.     /* Create and enable the render context */
  160.     p_vout->p_sys->hGLRC = wglCreateContext( p_vout->p_sys->hGLDC );
  161.     wglMakeCurrent( p_vout->p_sys->hGLDC, p_vout->p_sys->hGLRC );
  162.     return VLC_SUCCESS;
  163. }
  164. /*****************************************************************************
  165.  * End: terminate Sys video thread output method
  166.  *****************************************************************************
  167.  * Terminate an output method created by Create.
  168.  * It is called at the end of the thread.
  169.  *****************************************************************************/
  170. static void End( vout_thread_t *p_vout )
  171. {
  172.     wglMakeCurrent( NULL, NULL );
  173.     wglDeleteContext( p_vout->p_sys->hGLRC );
  174.     ReleaseDC( p_vout->p_sys->hvideownd, p_vout->p_sys->hGLDC );
  175.     return;
  176. }
  177. /*****************************************************************************
  178.  * CloseVideo: destroy Sys video thread output method
  179.  *****************************************************************************
  180.  * Terminate an output method created by Create
  181.  *****************************************************************************/
  182. static void CloseVideo( vlc_object_t *p_this )
  183. {
  184.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  185.     msg_Dbg( p_vout, "CloseVideo" );
  186.     if( p_vout->p_sys->p_event )
  187.     {
  188.         vlc_object_detach( p_vout->p_sys->p_event );
  189.         /* Kill DirectXEventThread */
  190.         p_vout->p_sys->p_event->b_die = VLC_TRUE;
  191.         /* we need to be sure DirectXEventThread won't stay stuck in
  192.          * GetMessage, so we send a fake message */
  193.         if( p_vout->p_sys->hwnd )
  194.         {
  195.             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
  196.         }
  197.         vlc_thread_join( p_vout->p_sys->p_event );
  198.         vlc_object_destroy( p_vout->p_sys->p_event );
  199.     }
  200.     vlc_mutex_destroy( &p_vout->p_sys->lock );
  201.     if( p_vout->p_sys )
  202.     {
  203.         free( p_vout->p_sys );
  204.         p_vout->p_sys = NULL;
  205.     }
  206. }
  207. /*****************************************************************************
  208.  * Manage: handle Sys events
  209.  *****************************************************************************
  210.  * This function should be called regularly by the video output thread.
  211.  * It returns a non null value if an error occurred.
  212.  *****************************************************************************/
  213. static int Manage( vout_thread_t *p_vout )
  214. {
  215.     WINDOWPLACEMENT window_placement;
  216.     int i_width = p_vout->p_sys->rect_dest.right -
  217.         p_vout->p_sys->rect_dest.left;
  218.     int i_height = p_vout->p_sys->rect_dest.bottom -
  219.         p_vout->p_sys->rect_dest.top;
  220.     glViewport( 0, 0, i_width, i_height );
  221.     /* If we do not control our window, we check for geometry changes
  222.      * ourselves because the parent might not send us its events. */
  223.     vlc_mutex_lock( &p_vout->p_sys->lock );
  224.     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
  225.     {
  226.         RECT rect_parent;
  227.         POINT point;
  228.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  229.         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
  230.         point.x = point.y = 0;
  231.         ClientToScreen( p_vout->p_sys->hparent, &point );
  232.         OffsetRect( &rect_parent, point.x, point.y );
  233.         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
  234.         {
  235.             p_vout->p_sys->rect_parent = rect_parent;
  236.             /* This one is to force the update even if only
  237.              * the position has changed */
  238.             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
  239.                           rect_parent.right - rect_parent.left,
  240.                           rect_parent.bottom - rect_parent.top, 0 );
  241.             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  242.                           rect_parent.right - rect_parent.left,
  243.                           rect_parent.bottom - rect_parent.top, 0 );
  244.         }
  245.     }
  246.     else
  247.     {
  248.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  249.     }
  250.     /* We used to call the Win32 PeekMessage function here to read the window
  251.      * messages. But since window can stay blocked into this function for a
  252.      * long time (for example when you move your window on the screen), I
  253.      * decided to isolate PeekMessage in another thread. */
  254.     /*
  255.      * Fullscreen change
  256.      */
  257.     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
  258.         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
  259.     {
  260.         vlc_value_t val;
  261.         HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
  262.             p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
  263.         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
  264.         /* We need to switch between Maximized and Normal sized window */
  265.         window_placement.length = sizeof(WINDOWPLACEMENT);
  266.         GetWindowPlacement( hwnd, &window_placement );
  267.         if( p_vout->b_fullscreen )
  268.         {
  269.             /* Change window style, no borders and no title bar */
  270.             int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
  271.             SetWindowLong( hwnd, GWL_STYLE, i_style );
  272.             if( p_vout->p_sys->hparent )
  273.             {
  274.                 /* Retrieve current window position so fullscreen will happen
  275.                  * on the right screen */
  276.                 POINT point = {0,0};
  277.                 RECT rect;
  278.                 ClientToScreen( p_vout->p_sys->hwnd, &point );
  279.                 GetClientRect( p_vout->p_sys->hwnd, &rect );
  280.                 SetWindowPos( hwnd, 0, point.x, point.y,
  281.                               rect.right, rect.bottom,
  282.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  283.                 GetWindowPlacement( hwnd, &window_placement );
  284.             }
  285.             /* Maximize window */
  286.             window_placement.showCmd = SW_SHOWMAXIMIZED;
  287.             SetWindowPlacement( hwnd, &window_placement );
  288.             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
  289.                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
  290.             if( p_vout->p_sys->hparent )
  291.             {
  292.                 RECT rect;
  293.                 GetClientRect( hwnd, &rect );
  294.                 SetParent( p_vout->p_sys->hwnd, hwnd );
  295.                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  296.                               rect.right, rect.bottom,
  297.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  298.             }
  299.             SetForegroundWindow( hwnd );
  300.         }
  301.         else
  302.         {
  303.             /* Change window style, no borders and no title bar */
  304.             int i_style = WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
  305.                 WS_SIZEBOX | WS_VISIBLE;
  306.             SetWindowLong( hwnd, GWL_STYLE, i_style );
  307.             /* Normal window */
  308.             window_placement.showCmd = SW_SHOWNORMAL;
  309.             SetWindowPlacement( hwnd, &window_placement );
  310.             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
  311.                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
  312.             if( p_vout->p_sys->hparent )
  313.             {
  314.                 RECT rect;
  315.                 GetClientRect( p_vout->p_sys->hparent, &rect );
  316.                 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
  317.                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  318.                               rect.right, rect.bottom,
  319.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  320.                 ShowWindow( hwnd, SW_HIDE );
  321.                 SetForegroundWindow( p_vout->p_sys->hparent );
  322.             }
  323.             /* Make sure the mouse cursor is displayed */
  324.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
  325.         }
  326.         /* Update the object variable and trigger callback */
  327.         val.b_bool = p_vout->b_fullscreen;
  328.         var_Set( p_vout, "fullscreen", val );
  329.         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  330.         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  331.     }
  332.     /*
  333.      * Pointer change
  334.      */
  335.     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
  336.         (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
  337.     {
  338.         POINT point;
  339.         HWND hwnd;
  340.         /* Hide the cursor only if it is inside our window */
  341.         GetCursorPos( &point );
  342.         hwnd = WindowFromPoint(point);
  343.         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
  344.         {
  345.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
  346.         }
  347.         else
  348.         {
  349.             p_vout->p_sys->i_lastmoved = mdate();
  350.         }
  351.     }
  352.     /*
  353.      * "Always on top" status change
  354.      */
  355.     if( p_vout->p_sys->b_on_top_change )
  356.     {
  357.         vlc_value_t val;
  358.         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
  359.         var_Get( p_vout, "video-on-top", &val );
  360.         /* Set the window on top if necessary */
  361.         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  362.                            & WS_EX_TOPMOST ) )
  363.         {
  364.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  365.                            MF_BYCOMMAND | MFS_CHECKED );
  366.             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  367.                           SWP_NOSIZE | SWP_NOMOVE );
  368.         }
  369.         else
  370.         /* The window shouldn't be on top */
  371.         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  372.                            & WS_EX_TOPMOST ) )
  373.         {
  374.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  375.                            MF_BYCOMMAND | MFS_UNCHECKED );
  376.             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  377.                           SWP_NOSIZE | SWP_NOMOVE );
  378.         }
  379.         p_vout->p_sys->b_on_top_change = VLC_FALSE;
  380.     }
  381.     /* Check if the event thread is still running */
  382.     if( p_vout->p_sys->p_event->b_die )
  383.     {
  384.         return VLC_EGENERIC; /* exit */
  385.     }
  386.     return VLC_SUCCESS;
  387. }
  388. /*****************************************************************************
  389.  * GLSwapBuffers: swap front/back buffers
  390.  *****************************************************************************/
  391. static void GLSwapBuffers( vout_thread_t *p_vout )
  392. {
  393.     SwapBuffers( p_vout->p_sys->hGLDC );
  394. }
  395. int DirectXUpdateOverlay( vout_thread_t *p_vout )
  396. {
  397.     return 1;
  398. }