vout_events.c 22.2 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * vout_events.c: Windows DirectX video output events handler
 *****************************************************************************
4
 * Copyright (C) 2001 VideoLAN
Gildas Bazin's avatar
 
Gildas Bazin committed
5
 * $Id: vout_events.c,v 1.25 2002/07/30 17:14:33 gbazin Exp $
Gildas Bazin's avatar
 
Gildas Bazin committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/


/*****************************************************************************
 * Preamble: This file contains the functions related to the creation of
 *             a window and the handling of its messages (events).
 *****************************************************************************/
#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
#include <string.h>                                            /* strerror() */

33 34 35
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include <vlc/vout.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
36

Gildas Bazin's avatar
 
Gildas Bazin committed
37 38 39 40
#include "netutils.h"

#include <windows.h>
#include <windowsx.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
41
#include <shellapi.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
42

Gildas Bazin's avatar
 
Gildas Bazin committed
43
#include <ddraw.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
44 45 46 47 48 49 50 51

#include "vout_directx.h"

/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
static int  DirectXCreateWindow( vout_thread_t *p_vout );
static void DirectXCloseWindow ( vout_thread_t *p_vout );
Gildas Bazin's avatar
 
Gildas Bazin committed
52
static void DirectXUpdateRects( vout_thread_t *p_vout );
Gildas Bazin's avatar
 
Gildas Bazin committed
53 54 55 56 57 58 59 60 61 62 63
static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message,
                                          WPARAM wParam, LPARAM lParam );

/*****************************************************************************
 * DirectXEventThread: Create video window & handle its messages
 *****************************************************************************
 * This function creates a video window and then enters an infinite loop
 * that handles the messages sent to that window.
 * The main goal of this thread is to isolate the Win32 PeekMessage function
 * because this one can block for a long time.
 *****************************************************************************/
64
void DirectXEventThread( event_thread_t *p_event )
Gildas Bazin's avatar
 
Gildas Bazin committed
65
{
Gildas Bazin's avatar
 
Gildas Bazin committed
66 67
    MSG msg;
    POINT old_mouse_pos;
Gildas Bazin's avatar
 
Gildas Bazin committed
68 69 70 71 72 73

    /* Initialisation */

    /* Create a window for the video */
    /* Creating a window under Windows also initializes the thread's event
     * message qeue */
74
    if( DirectXCreateWindow( p_event->p_vout ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
75
    {
76 77
        msg_Err( p_event, "out of memory" );
        p_event->b_dead = 1;
Gildas Bazin's avatar
 
Gildas Bazin committed
78 79 80
    }

    /* signal the creation of the window */
81
    vlc_thread_ready( p_event );
Gildas Bazin's avatar
 
Gildas Bazin committed
82 83

    /* Main loop */
Gildas Bazin's avatar
 
Gildas Bazin committed
84
    /* GetMessage will sleep if there's no message in the queue */
85 86
    while( !p_event->b_die
           && GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
87
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
88
        /* Check if we are asked to exit */
89
        if( p_event->b_die )
Gildas Bazin's avatar
 
Gildas Bazin committed
90 91 92
            break;

        switch( msg.message )
Gildas Bazin's avatar
 
Gildas Bazin committed
93
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
94

Gildas Bazin's avatar
 
Gildas Bazin committed
95
        case WM_NCMOUSEMOVE:
Gildas Bazin's avatar
 
Gildas Bazin committed
96
        case WM_MOUSEMOVE:
Gildas Bazin's avatar
 
Gildas Bazin committed
97 98
            if( (abs(GET_X_LPARAM(msg.lParam) - old_mouse_pos.x) > 2 ||
                (abs(GET_Y_LPARAM(msg.lParam) - old_mouse_pos.y)) > 2 ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
99
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
100
                GetCursorPos( &old_mouse_pos );
101
                p_event->p_vout->p_sys->i_lastmoved = mdate();
Gildas Bazin's avatar
 
Gildas Bazin committed
102

103
                if( p_event->p_vout->p_sys->b_cursor_hidden )
Gildas Bazin's avatar
 
Gildas Bazin committed
104
                {
105
                    p_event->p_vout->p_sys->b_cursor_hidden = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
106
                    ShowCursor( TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
107
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
108
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
109 110 111 112 113
            break;

        case WM_VLC_HIDE_MOUSE:
            GetCursorPos( &old_mouse_pos );
            ShowCursor( FALSE );
Gildas Bazin's avatar
 
Gildas Bazin committed
114 115 116
            break;

        case WM_RBUTTONUP:
117 118
            {
                intf_thread_t *p_intf;
119 120
                p_intf = vlc_object_find( p_event, VLC_OBJECT_INTF,
                                                   FIND_ANYWHERE );
121 122 123 124 125 126
                if( p_intf )
                {
                    p_intf->b_menu_change = 1;
                    vlc_object_release( p_intf );
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
127 128
            break;

Gildas Bazin's avatar
 
Gildas Bazin committed
129 130 131 132
        case WM_LBUTTONDOWN:
            break;

        case WM_LBUTTONDBLCLK:
133
            p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
134 135
            break;

Gildas Bazin's avatar
 
Gildas Bazin committed
136 137 138 139
        case WM_KEYDOWN:
            /* the key events are first processed here. The next
             * message processed by this main message loop will be the
             * char translation of the key event */
140
            msg_Dbg( p_event, "WM_KEYDOWN" );
Gildas Bazin's avatar
 
Gildas Bazin committed
141 142 143
            switch( msg.wParam )
            {
            case VK_ESCAPE:
Gildas Bazin's avatar
 
Gildas Bazin committed
144
                /* exit application */
145
                p_event->p_vlc->b_die = 1;
Gildas Bazin's avatar
 
Gildas Bazin committed
146
                break;
Sam Hocevar's avatar
Sam Hocevar committed
147 148 149 150 151 152 153 154 155 156 157 158 159

            case VK_F1: network_ChannelJoin( p_event, 1 ); break;
            case VK_F2: network_ChannelJoin( p_event, 2 ); break;
            case VK_F3: network_ChannelJoin( p_event, 3 ); break;
            case VK_F4: network_ChannelJoin( p_event, 4 ); break;
            case VK_F5: network_ChannelJoin( p_event, 5 ); break;
            case VK_F6: network_ChannelJoin( p_event, 6 ); break;
            case VK_F7: network_ChannelJoin( p_event, 7 ); break;
            case VK_F8: network_ChannelJoin( p_event, 8 ); break;
            case VK_F9: network_ChannelJoin( p_event, 9 ); break;
            case VK_F10: network_ChannelJoin( p_event, 10 ); break;
            case VK_F11: network_ChannelJoin( p_event, 11 ); break;
            case VK_F12: network_ChannelJoin( p_event, 12 ); break;
Gildas Bazin's avatar
 
Gildas Bazin committed
160 161 162 163 164 165 166 167 168
            }
            TranslateMessage(&msg);
            break;

        case WM_CHAR:
            switch( msg.wParam )
            {
            case 'q':
            case 'Q':
Gildas Bazin's avatar
 
Gildas Bazin committed
169
                /* exit application */
170
                p_event->p_vlc->b_die = 1;
Gildas Bazin's avatar
 
Gildas Bazin committed
171
                break;
Gildas Bazin's avatar
 
Gildas Bazin committed
172 173 174

            case 'f':                            /* switch to fullscreen */
            case 'F':
175
                p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
176
                break;
Gildas Bazin's avatar
 
Gildas Bazin committed
177 178 179

            case 'c':                                /* toggle grayscale */
            case 'C':
180 181
                p_event->p_vout->b_grayscale = ! p_event->p_vout->b_grayscale;
                p_event->p_vout->p_sys->i_changes |= VOUT_GRAYSCALE_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
182
                break;
Gildas Bazin's avatar
 
Gildas Bazin committed
183 184 185

            case 'i':                                     /* toggle info */
            case 'I':
186 187
                p_event->p_vout->b_info = ! p_event->p_vout->b_info;
                p_event->p_vout->p_sys->i_changes |= VOUT_INFO_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
188 189
                break;

Gildas Bazin's avatar
 
Gildas Bazin committed
190 191
            case 's':                                  /* toggle scaling */
            case 'S':
192 193
                p_event->p_vout->b_scale = ! p_event->p_vout->b_scale;
                p_event->p_vout->p_sys->i_changes |= VOUT_SCALE_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
194
                break;
Gildas Bazin's avatar
 
Gildas Bazin committed
195 196

            case ' ':                                /* toggle interface */
197 198
                p_event->p_vout->b_interface = ! p_event->p_vout->b_interface;
                p_event->p_vout->p_sys->i_changes |= VOUT_INTF_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
199 200
                break;

Gildas Bazin's avatar
 
Gildas Bazin committed
201 202
            default:
                break;
Gildas Bazin's avatar
 
Gildas Bazin committed
203 204
            }

Gildas Bazin's avatar
 
Gildas Bazin committed
205 206 207 208 209 210
        default:
            /* Messages we don't handle directly are dispatched to the
             * window procedure */
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            break;
Gildas Bazin's avatar
 
Gildas Bazin committed
211

Gildas Bazin's avatar
 
Gildas Bazin committed
212
        } /* End Switch */
Gildas Bazin's avatar
 
Gildas Bazin committed
213 214 215

    } /* End Main loop */

Gildas Bazin's avatar
 
Gildas Bazin committed
216 217
    if( msg.message == WM_QUIT )
    {
218 219
        msg_Warn( p_event, "WM_QUIT... should not happen!!" );
        p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
Gildas Bazin's avatar
 
Gildas Bazin committed
220 221
    }

222
    msg_Dbg( p_event, "DirectXEventThread Terminating" );
Gildas Bazin's avatar
 
Gildas Bazin committed
223

Gildas Bazin's avatar
 
Gildas Bazin committed
224
    /* clear the changes formerly signaled */
225
    p_event->p_vout->p_sys->i_changes = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
226

227
    DirectXCloseWindow( p_event->p_vout );
Gildas Bazin's avatar
 
Gildas Bazin committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
}


/* following functions are local */

/*****************************************************************************
 * DirectXCreateWindow: create a window for the video.
 *****************************************************************************
 * Before creating a direct draw surface, we need to create a window in which
 * the video will be displayed. This window will also allow us to capture the
 * events.
 *****************************************************************************/
static int DirectXCreateWindow( vout_thread_t *p_vout )
{
    HINSTANCE  hInstance;
    WNDCLASSEX wc;                                /* window class components */
    RECT       rect_window;
    COLORREF   colorkey; 
    HDC        hdc;
Gildas Bazin's avatar
 
Gildas Bazin committed
247 248
    HICON      vlc_icon = NULL;
    char       vlc_path[_MAX_PATH+1];
Gildas Bazin's avatar
 
Gildas Bazin committed
249

250
    msg_Dbg( p_vout, "DirectXCreateWindow" );
Gildas Bazin's avatar
 
Gildas Bazin committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

    /* get this module's instance */
    hInstance = GetModuleHandle(NULL);

    /* Create a BRUSH that will be used by Windows to paint the window
     * background.
     * This window background is important for us as it will be used by the
     * graphics card to display the overlay.
     * This is why we carefully choose the color for this background, the goal
     * being to choose a color which isn't complete black but nearly. We
     * obviously don't want to use black as a colorkey for the overlay because
     * black is one of the most used color and thus would give us undesirable
     * effects */
    /* the first step is to find the colorkey we want to use. The difficulty
     * comes from the potential dithering (depends on the display depth)
     * because we need to know the real RGB value of the chosen colorkey */
Gildas Bazin's avatar
 
Gildas Bazin committed
267
    hdc = GetDC( NULL );
Gildas Bazin's avatar
 
Gildas Bazin committed
268 269 270 271 272
    for( colorkey = 5; colorkey < 0xFF /*all shades of red*/; colorkey++ )
    {
        if( colorkey == GetNearestColor( hdc, colorkey ) )
          break;
    }
273
    msg_Dbg( p_vout, "background color: %i", colorkey );
Gildas Bazin's avatar
 
Gildas Bazin committed
274 275 276

    /* create the actual brush */  
    p_vout->p_sys->hbrush = CreateSolidBrush(colorkey);
Gildas Bazin's avatar
 
Gildas Bazin committed
277 278 279 280 281 282
    p_vout->p_sys->i_rgb_colorkey = (int)colorkey;

    /* Get the current size of the display and its colour depth */
    p_vout->p_sys->rect_display.right = GetDeviceCaps( hdc, HORZRES );
    p_vout->p_sys->rect_display.bottom = GetDeviceCaps( hdc, VERTRES );
    p_vout->p_sys->i_display_depth = GetDeviceCaps( hdc, BITSPIXEL );
283 284 285 286
    msg_Dbg( p_vout, "screen dimensions %ix%i colour depth %i",
                      p_vout->p_sys->rect_display.right,
                      p_vout->p_sys->rect_display.bottom,
                      p_vout->p_sys->i_display_depth );
Gildas Bazin's avatar
 
Gildas Bazin committed
287

Gildas Bazin's avatar
 
Gildas Bazin committed
288
    ReleaseDC( NULL, hdc );
Gildas Bazin's avatar
 
Gildas Bazin committed
289 290

    /* Get the Icon from the main app */
Gildas Bazin's avatar
 
Gildas Bazin committed
291
    vlc_icon = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
292 293 294 295 296
    if( GetModuleFileName( NULL, vlc_path, _MAX_PATH ) )
    {
        vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
297 298 299

    /* fill in the window class structure */
    wc.cbSize        = sizeof(WNDCLASSEX);
Gildas Bazin's avatar
 
Gildas Bazin committed
300
    wc.style         = CS_DBLCLKS;                       /* style: dbl click */
Gildas Bazin's avatar
 
Gildas Bazin committed
301 302 303 304
    wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;           /* event handler */
    wc.cbClsExtra    = 0;                             /* no extra class data */
    wc.cbWndExtra    = 0;                            /* no extra window data */
    wc.hInstance     = hInstance;                                /* instance */
Gildas Bazin's avatar
 
Gildas Bazin committed
305
    wc.hIcon         = vlc_icon;                        /* load the vlc icon */
Gildas Bazin's avatar
 
Gildas Bazin committed
306 307 308 309
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
    wc.hbrBackground = p_vout->p_sys->hbrush;            /* background color */
    wc.lpszMenuName  = NULL;                                      /* no menu */
    wc.lpszClassName = "VLC DirectX";                 /* use a special class */
Gildas Bazin's avatar
 
Gildas Bazin committed
310
    wc.hIconSm       = vlc_icon;                        /* load the vlc icon */
Gildas Bazin's avatar
 
Gildas Bazin committed
311 312 313 314

    /* register the window class */
    if (!RegisterClassEx(&wc))
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
315
        WNDCLASS wndclass;
Gildas Bazin's avatar
 
Gildas Bazin committed
316 317 318 319 320 321 322 323 324 325 326 327

        /* free window background brush */
        if( p_vout->p_sys->hbrush )
        {
            DeleteObject( p_vout->p_sys->hbrush );
            p_vout->p_sys->hbrush = NULL;
        }

        if( vlc_icon )
            DestroyIcon( vlc_icon );

        /* Check why it failed. If it's because one already exists then fine */
Gildas Bazin's avatar
 
Gildas Bazin committed
328 329
        if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
        {
330
            msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
Gildas Bazin's avatar
 
Gildas Bazin committed
331 332
            return (1);
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346
    }

    /* when you create a window you give the dimensions you wish it to have.
     * Unfortunatly these dimensions will include the borders and title bar.
     * We use the following function to find out the size of the window
     * corresponding to the useable surface we want */
    rect_window.top    = 10;
    rect_window.left   = 10;
    rect_window.right  = rect_window.left + p_vout->p_sys->i_window_width;
    rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
    AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );

    /* create the window */
    p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
Gildas Bazin's avatar
 
Gildas Bazin committed
347
                    VOUT_TITLE " (DirectX Output)", /* window title bar text */
Gildas Bazin's avatar
 
Gildas Bazin committed
348
                    WS_OVERLAPPEDWINDOW
Gildas Bazin's avatar
 
Gildas Bazin committed
349
                    | WS_SIZEBOX,               /* window style */
Gildas Bazin's avatar
 
Gildas Bazin committed
350 351
                    CW_USEDEFAULT,                   /* default X coordinate */
                    0,                               /* default Y coordinate */
Gildas Bazin's avatar
 
Gildas Bazin committed
352 353 354 355 356 357 358 359
                    rect_window.right - rect_window.left,    /* window width */
                    rect_window.bottom - rect_window.top,   /* window height */
                    NULL,                                /* no parent window */
                    NULL,                          /* no menu in this window */
                    hInstance,            /* handle of this program instance */
                    NULL);                        /* no additional arguments */

    if (p_vout->p_sys->hwnd == NULL) {
360
        msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
Gildas Bazin's avatar
 
Gildas Bazin committed
361 362 363
        return (1);
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
364 365 366 367 368
    /* store a p_vout pointer into the window local storage (for later use
     * in DirectXEventProc).
     * We need to use SetWindowLongPtr when it is available in mingw */
    SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout );

Gildas Bazin's avatar
 
Gildas Bazin committed
369 370 371 372 373 374 375 376 377 378 379 380 381
    /* now display the window */
    ShowWindow(p_vout->p_sys->hwnd, SW_SHOW);

    return ( 0 );
}

/*****************************************************************************
 * DirectXCloseWindow: close the window created by DirectXCreateWindow
 *****************************************************************************
 * This function returns all resources allocated by DirectXCreateWindow.
 *****************************************************************************/
static void DirectXCloseWindow( vout_thread_t *p_vout )
{
382
    msg_Dbg( p_vout, "DirectXCloseWindow" );
Gildas Bazin's avatar
 
Gildas Bazin committed
383

Gildas Bazin's avatar
 
Gildas Bazin committed
384 385
    if( p_vout->p_sys->hwnd != NULL )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
386
        DestroyWindow( p_vout->p_sys->hwnd );
Gildas Bazin's avatar
 
Gildas Bazin committed
387 388 389
        p_vout->p_sys->hwnd = NULL;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
390 391 392
    /* We don't unregister the Window Class because it could lead to race
     * conditions and it will be done anyway by the system when the app will
     * exit */
Gildas Bazin's avatar
 
Gildas Bazin committed
393 394
}

Gildas Bazin's avatar
 
Gildas Bazin committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
/*****************************************************************************
 * DirectXUpdateRects: 
 *****************************************************************************
 * This function is called when the window position and size is changed, and
 * its job is to update the source and destination RECTs used to display the
 * picture.
 *****************************************************************************/
static void DirectXUpdateRects( vout_thread_t *p_vout )
{
    int i_width, i_height, i_x, i_y;

#define rect_src p_vout->p_sys->rect_src
#define rect_src_clipped p_vout->p_sys->rect_src_clipped
#define rect_dest p_vout->p_sys->rect_dest
#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
#define rect_display p_vout->p_sys->rect_display

    vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width,
                       p_vout->p_sys->i_window_height,
                       &i_x, &i_y, &i_width, &i_height );

    /* Destination image position and dimensions */
    rect_dest.left = i_x + p_vout->p_sys->i_window_x;
    rect_dest.top = i_y + p_vout->p_sys->i_window_y;
    rect_dest.right = rect_dest.left + i_width;
    rect_dest.bottom = rect_dest.top + i_height;


    /* UpdateOverlay directdraw function doesn't automatically clip to the
     * display size so we need to do it otherwise it will fails */

    /* Clip the destination window */
    IntersectRect( &rect_dest_clipped, &rect_dest, &rect_display );

Gildas Bazin's avatar
 
Gildas Bazin committed
429
#if 0
430 431 432 433
    msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
                     " %i,%i,%i,%i",
                     rect_dest_clipped.left, rect_dest_clipped.top,
                     rect_dest_clipped.right, rect_dest_clipped.bottom );
Gildas Bazin's avatar
 
Gildas Bazin committed
434
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461

    /* the 2 following lines are to fix a bug when clicking on the desktop */
    if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
        (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
    {
        SetRectEmpty( &rect_src_clipped );
        return;
    }

    /* src image dimensions */
    rect_src.left = 0;
    rect_src.top = 0;
    rect_src.right = p_vout->render.i_width;
    rect_src.bottom = p_vout->render.i_height;

    /* Clip the source image */
    rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
      p_vout->render.i_width / (rect_dest.right - rect_dest.left);
    rect_src_clipped.right = p_vout->render.i_width - 
      (rect_dest.right - rect_dest_clipped.right) * p_vout->render.i_width /
      (rect_dest.right - rect_dest.left);
    rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
      p_vout->render.i_height / (rect_dest.bottom - rect_dest.top);
    rect_src_clipped.bottom = p_vout->render.i_height -
      (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->render.i_height /
      (rect_dest.bottom - rect_dest.top);

Gildas Bazin's avatar
 
Gildas Bazin committed
462
#if 0
463 464 465 466
    msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
                     " coords: %i,%i,%i,%i",
                     rect_src_clipped.left, rect_src_clipped.top,
                     rect_src_clipped.right, rect_src_clipped.bottom );
Gildas Bazin's avatar
 
Gildas Bazin committed
467
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
468 469 470 471 472 473 474 475

#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
#undef rect_display
}

Gildas Bazin's avatar
 
Gildas Bazin committed
476 477 478 479 480 481 482
/*****************************************************************************
 * DirectXEventProc: This is the window event processing function.
 *****************************************************************************
 * On Windows, when you create a window you have to attach an event processing
 * function to it. The aim of this function is to manage "Queued Messages" and
 * "Nonqueued Messages".
 * Queued Messages are those picked up and retransmitted by vout_Manage
Gildas Bazin's avatar
 
Gildas Bazin committed
483
 * (using the GetMessage and DispatchMessage functions).
Gildas Bazin's avatar
 
Gildas Bazin committed
484
 * Nonqueued Messages are those that Windows will send directly to this
Gildas Bazin's avatar
 
Gildas Bazin committed
485
 * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
Gildas Bazin's avatar
 
Gildas Bazin committed
486 487 488 489
 *****************************************************************************/
static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
                                         WPARAM wParam, LPARAM lParam )
{
490 491
    vout_thread_t *p_vout =
            (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
Gildas Bazin's avatar
 
Gildas Bazin committed
492

Gildas Bazin's avatar
 
Gildas Bazin committed
493 494 495
    switch( message )
    {

Gildas Bazin's avatar
 
Gildas Bazin committed
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
    case WM_WINDOWPOSCHANGED:
        {
        RECT     rect_window;
        POINT    point_window;

        /* update the window position */
        point_window.x = 0;
        point_window.y = 0;
        ClientToScreen( hwnd, &point_window );
        p_vout->p_sys->i_window_x = point_window.x;
        p_vout->p_sys->i_window_y = point_window.y;

        /* update the window size */
        GetClientRect( hwnd, &rect_window );
        p_vout->p_sys->i_window_width = rect_window.right;
        p_vout->p_sys->i_window_height = rect_window.bottom;

        DirectXUpdateRects( p_vout );
Gildas Bazin's avatar
 
Gildas Bazin committed
514
        if( p_vout->p_sys->b_using_overlay &&
Gildas Bazin's avatar
 
Gildas Bazin committed
515
            !p_vout->p_sys->p_event->b_die )
Gildas Bazin's avatar
 
Gildas Bazin committed
516 517 518
            DirectXUpdateOverlay( p_vout );

        /* signal the size change */
Gildas Bazin's avatar
 
Gildas Bazin committed
519
        if( !p_vout->p_sys->b_using_overlay &&
Gildas Bazin's avatar
 
Gildas Bazin committed
520
            !p_vout->p_sys->p_event->b_die )
Gildas Bazin's avatar
 
Gildas Bazin committed
521
            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
Gildas Bazin's avatar
 
Gildas Bazin committed
522 523 524

        return 0;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
525 526 527 528
        break;

    /* the user wants to close the window */
    case WM_CLOSE:
529
        msg_Dbg( p_vout, "WinProc WM_CLOSE" );
Gildas Bazin's avatar
 
Gildas Bazin committed
530
        /* exit application */
531 532 533 534 535 536 537 538 539
        p_vout->p_vlc->b_die = 1;
        return 0;
        break;

    /* the window has been closed so shut down everything now */
    case WM_DESTROY:
        msg_Dbg( p_vout, "WinProc WM_DESTROY" );
        /* just destroy the window */
        PostQuitMessage( 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
540
        return 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
541 542 543 544 545 546 547
        break;

    case WM_SYSCOMMAND:
        switch (wParam)
        {
            case SC_SCREENSAVE:                     /* catch the screensaver */
            case SC_MONITORPOWER:              /* catch the monitor turn-off */
548
            msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" );
Gildas Bazin's avatar
 
Gildas Bazin committed
549 550 551 552
            return 0;                      /* this stops them from happening */
        }
        break;

Gildas Bazin's avatar
 
Gildas Bazin committed
553 554 555 556 557 558 559 560 561
    case WM_ERASEBKGND:
        if( !p_vout->p_sys->b_using_overlay )
        {
            /* We want to eliminate unnecessary background redraws which create
             * an annoying flickering */
            int i_width, i_height, i_x, i_y;
            RECT rect_temp;
            GetClipBox( (HDC)wParam, &rect_temp );
#if 0
562
            msg_Dbg( p_vout, "WinProc WM_ERASEBKGND %i,%i,%i,%i",
Gildas Bazin's avatar
 
Gildas Bazin committed
563 564 565 566 567 568 569 570 571 572 573
                          rect_temp.left, rect_temp.top,
                          rect_temp.right, rect_temp.bottom );
#endif
            vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width,
                               p_vout->p_sys->i_window_height,
                               &i_x, &i_y, &i_width, &i_height );
            ExcludeClipRect( (HDC)wParam, i_x, i_y,
                             i_x + i_width, i_y + i_height );
        }
        break;

Gildas Bazin's avatar
 
Gildas Bazin committed
574
    default:
575
        //msg_Dbg( p_vout, "WinProc WM Default %i", message );
Gildas Bazin's avatar
 
Gildas Bazin committed
576 577 578 579 580
        break;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}