events.c 26.8 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * events.c: Windows DirectX video output events handler
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
gbazin's avatar
 
gbazin committed
5
 * $Id: events.c,v 1.26 2003/10/29 01:33:27 gbazin Exp $
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 33 34
 *
 * 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() */

#include <vlc/vlc.h>
#include <vlc/intf.h>
35
#include <vlc/input.h>
36 37 38 39 40 41 42 43
#include <vlc/vout.h>

#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>

#include <ddraw.h>

44
#include "vlc_keys.h"
45 46 47 48 49 50 51 52 53 54
#include "vout.h"

/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
static int  DirectXCreateWindow( vout_thread_t *p_vout );
static void DirectXCloseWindow ( vout_thread_t *p_vout );
static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message,
                                          WPARAM wParam, LPARAM lParam );

55 56 57 58 59 60 61 62 63 64 65 66 67
static void DirectXPopupMenu( event_thread_t *p_event, vlc_bool_t b_open )
{
    playlist_t *p_playlist =
        vlc_object_find( p_event, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
    if( p_playlist != NULL )
    {
        vlc_value_t val;
        val.b_bool = b_open;
        var_Set( p_playlist, "intf-popupmenu", val );
        vlc_object_release( p_playlist );
    }
}

68 69
static int DirectXConvertKey( int i_key );

70 71 72 73 74 75 76 77 78 79 80
/*****************************************************************************
 * 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.
 *****************************************************************************/
void DirectXEventThread( event_thread_t *p_event )
{
    MSG msg;
gbazin's avatar
 
gbazin committed
81
    POINT old_mouse_pos = {0,0};
82 83
    vlc_value_t val;
    int i_width, i_height, i_x, i_y;
84 85 86 87 88

    /* Initialisation */

    /* Create a window for the video */
    /* Creating a window under Windows also initializes the thread's event
89
     * message queue */
90 91 92
    if( DirectXCreateWindow( p_event->p_vout ) )
    {
        msg_Err( p_event, "out of memory" );
93
        p_event->b_dead = VLC_TRUE;
94 95 96 97 98 99 100
    }

    /* signal the creation of the window */
    vlc_thread_ready( p_event );

    /* Main loop */
    /* GetMessage will sleep if there's no message in the queue */
101 102
    while( !p_event->b_die && ( p_event->p_vout->p_sys->hparent ||
           GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) ) )
103 104 105 106 107
    {
        /* Check if we are asked to exit */
        if( p_event->b_die )
            break;

108 109
        if( p_event->p_vout->p_sys->hparent ) msleep( INTF_IDLE_SLEEP );

110 111 112 113 114
        switch( msg.message )
        {

        case WM_NCMOUSEMOVE:
        case WM_MOUSEMOVE:
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
            vout_PlacePicture( p_event->p_vout,
                               p_event->p_vout->p_sys->i_window_width,
                               p_event->p_vout->p_sys->i_window_height,
                               &i_x, &i_y, &i_width, &i_height );

            val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x )
                         * p_event->p_vout->render.i_width / i_width;
            var_Set( p_event->p_vout, "mouse-x", val );
            val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y )
                         * p_event->p_vout->render.i_height / i_height;
            var_Set( p_event->p_vout, "mouse-y", val );

            val.b_bool = VLC_TRUE;
            var_Set( p_event->p_vout, "mouse-moved", val );

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
            if( (abs(GET_X_LPARAM(msg.lParam) - old_mouse_pos.x) > 2 ||
                (abs(GET_Y_LPARAM(msg.lParam) - old_mouse_pos.y)) > 2 ) )
            {
                GetCursorPos( &old_mouse_pos );
                p_event->p_vout->p_sys->i_lastmoved = mdate();

                if( p_event->p_vout->p_sys->b_cursor_hidden )
                {
                    p_event->p_vout->p_sys->b_cursor_hidden = 0;
                    ShowCursor( TRUE );
                }
            }
            break;

        case WM_VLC_HIDE_MOUSE:
            GetCursorPos( &old_mouse_pos );
            ShowCursor( FALSE );
            break;

gbazin's avatar
 
gbazin committed
149 150 151 152
        case WM_LBUTTONDOWN:
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int |= 1;
            var_Set( p_event->p_vout, "mouse-button-down", val );
153
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
            break;

        case WM_LBUTTONUP:
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int &= ~1;
            var_Set( p_event->p_vout, "mouse-button-down", val );

            val.b_bool = VLC_TRUE;
            var_Set( p_event->p_vout, "mouse-clicked", val );
            break;

        case WM_LBUTTONDBLCLK:
            p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
            break;

        case WM_MBUTTONDOWN:
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int |= 2;
            var_Set( p_event->p_vout, "mouse-button-down", val );
173
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
174 175 176 177 178 179 180 181 182 183 184 185
            break;

        case WM_MBUTTONUP:
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int &= ~2;
            var_Set( p_event->p_vout, "mouse-button-down", val );
            break;

        case WM_RBUTTONDOWN:
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int |= 4;
            var_Set( p_event->p_vout, "mouse-button-down", val );
186
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
187 188
            break;

189
        case WM_RBUTTONUP:
gbazin's avatar
 
gbazin committed
190 191 192
            var_Get( p_event->p_vout, "mouse-button-down", &val );
            val.i_int &= ~4;
            var_Set( p_event->p_vout, "mouse-button-down", val );
193
            DirectXPopupMenu( p_event, VLC_TRUE );
194 195 196 197 198 199
            break;

        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 */
200 201
        case WM_CHAR:
            if( msg.message == WM_KEYDOWN )
202
            {
203 204 205 206
                val.i_int = DirectXConvertKey( msg.wParam );
                TranslateMessage(&msg);
            }
            else val.i_int = msg.wParam;
207

208 209 210
            if( val.i_int )
            {
                if( GetKeyState(VK_CONTROL) & 0x8000 )
211
                {
212
                    val.i_int |= KEY_MODIFIER_CTRL;
213
                }
214
                else if( GetKeyState(VK_SHIFT) & 0x8000 )
gbazin's avatar
 
gbazin committed
215
                {
216
                    val.i_int |= KEY_MODIFIER_SHIFT;
gbazin's avatar
 
gbazin committed
217
                }
218
                else if( GetKeyState(VK_MENU) & 0x8000 )
gbazin's avatar
 
gbazin committed
219
                {
220
                    val.i_int |= KEY_MODIFIER_ALT;
gbazin's avatar
 
gbazin committed
221
                }
222

gbazin's avatar
 
gbazin committed
223
                var_Set( p_event->p_vlc, "key-pressed", val );
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
            }
            break;

        default:
            /* Messages we don't handle directly are dispatched to the
             * window procedure */
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            break;

        } /* End Switch */

    } /* End Main loop */

    if( msg.message == WM_QUIT )
    {
        msg_Warn( p_event, "WM_QUIT... should not happen!!" );
        p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
    }

244
    msg_Dbg( p_event, "DirectXEventThread terminating" );
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

    /* clear the changes formerly signaled */
    p_event->p_vout->p_sys->i_changes = 0;

    DirectXCloseWindow( p_event->p_vout );
}


/* 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;
265
    COLORREF   colorkey;
266
    HDC        hdc;
267
    HMENU      hMenu;
268
    RECT       rect_window;
269

270 271
    vlc_value_t val;

272 273
    msg_Dbg( p_vout, "DirectXCreateWindow" );

274
    /* Get this module's instance */
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    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 */
    hdc = GetDC( NULL );
290
    for( colorkey = 0x0a; colorkey < 0xff /* all shades of red */; colorkey++ )
291 292
    {
        if( colorkey == GetNearestColor( hdc, colorkey ) )
293 294 295
        {
            break;
        }
296 297 298
    }
    msg_Dbg( p_vout, "background color: %i", colorkey );

299
    /* Create the actual brush */
300 301 302 303 304 305 306 307 308 309 310 311 312 313
    p_vout->p_sys->hbrush = CreateSolidBrush(colorkey);
    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 );
    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 );

    ReleaseDC( NULL, hdc );

314
    /* If an external window was specified, we'll draw in it. */
315
    var_Get( p_vout->p_vlc, "drawable", &val );
316
    p_vout->p_sys->hparent = p_vout->p_sys->hwnd =
317
             val.i_int ?  (void*)(ptrdiff_t) val.i_int : NULL;
318 319

    if( p_vout->p_sys->hparent )
320
    {
321 322 323 324 325 326 327 328 329 330
        msg_Dbg( p_vout, "using external window %p\n", p_vout->p_sys->hwnd );

        /* Set stuff in the window that we can not put directly in
         * a class (see below). */
        SetClassLong( p_vout->p_sys->hwnd,
                      GCL_STYLE, CS_DBLCLKS );
        SetClassLong( p_vout->p_sys->hwnd,
                      GCL_HBRBACKGROUND, (LONG)p_vout->p_sys->hbrush );
        SetClassLong( p_vout->p_sys->hwnd,
                      GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW) );
331 332 333 334
        /* Store a p_vout pointer into the window local storage (for later
         * use in DirectXEventProc). */
        SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout );

335 336 337 338 339 340 341
        p_vout->p_sys->pf_wndproc =
               (WNDPROC)SetWindowLong( p_vout->p_sys->hwnd,
                                       GWL_WNDPROC, (LONG)DirectXEventProc );

        /* Blam! Erase everything that might have been there. */
        RedrawWindow( p_vout->p_sys->hwnd, NULL, NULL,
                      RDW_INVALIDATE | RDW_ERASE );
342
    }
343
    else
344
    {
345 346 347
        WNDCLASSEX wc;                            /* window class components */
        HICON      vlc_icon = NULL;
        char       vlc_path[MAX_PATH+1];
348

349 350 351
        /* Get the Icon from the main app */
        vlc_icon = NULL;
        if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
352
        {
353
            vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
354 355
        }

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
        /* Fill in the window class structure */
        wc.cbSize        = sizeof(WNDCLASSEX);
        wc.style         = CS_DBLCLKS;                   /* style: dbl click */
        wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;       /* event handler */
        wc.cbClsExtra    = 0;                         /* no extra class data */
        wc.cbWndExtra    = 0;                        /* no extra window data */
        wc.hInstance     = hInstance;                            /* instance */
        wc.hIcon         = vlc_icon;                /* load the vlc big icon */
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    /* default cursor */
        wc.hbrBackground = p_vout->p_sys->hbrush;        /* background color */
        wc.lpszMenuName  = NULL;                                  /* no menu */
        wc.lpszClassName = "VLC DirectX";             /* use a special class */
        wc.hIconSm       = vlc_icon;              /* load the vlc small icon */

        /* Register the window class */
        if( !RegisterClassEx(&wc) )
372
        {
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
            WNDCLASS wndclass;

            /* 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, otherwise return with an error. */
            if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
            {
                msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
                return VLC_EGENERIC;
            }
394 395
        }

396 397 398 399 400 401 402 403 404 405 406 407 408
        /* When you create a window you give the dimensions you wish it to
         * have. Unfortunatly these dimensions will include the borders and
         * titlebar. 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 */
409
                    VOUT_TITLE " (DirectX Output)", /* window title bar text */
410
                    WS_OVERLAPPEDWINDOW | WS_SIZEBOX,        /* window style */
411 412 413 414 415 416 417
                    CW_USEDEFAULT,                   /* default X coordinate */
                    0,                               /* default Y coordinate */
                    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 */
418
                    (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
419

420 421 422 423 424
        if( !p_vout->p_sys->hwnd )
        {
            msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
            return VLC_EGENERIC;
        }
425 426
    }

427
    /* Append a "Always On Top" entry in the system menu */
428 429
    hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
    AppendMenu( hMenu, MF_SEPARATOR, 0, "" );
430 431
    AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
                       IDM_TOGGLE_ON_TOP, "Always on &Top" );
432

433 434
    /* Now display the window */
    ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
435

436
    return VLC_SUCCESS;
437 438 439 440 441 442 443 444 445 446 447
}

/*****************************************************************************
 * DirectXCloseWindow: close the window created by DirectXCreateWindow
 *****************************************************************************
 * This function returns all resources allocated by DirectXCreateWindow.
 *****************************************************************************/
static void DirectXCloseWindow( vout_thread_t *p_vout )
{
    msg_Dbg( p_vout, "DirectXCloseWindow" );

448
    if( p_vout->p_sys->hwnd && !p_vout->p_sys->hparent )
449 450 451
    {
        DestroyWindow( p_vout->p_sys->hwnd );
    }
452 453 454 455 456 457 458 459 460
    else if( p_vout->p_sys->hparent )
    {
        /* We don't want our windowproc to be called anymore */
        SetWindowLong( p_vout->p_sys->hwnd,
                       GWL_WNDPROC, (LONG)p_vout->p_sys->pf_wndproc );

        /* Blam! Erase everything that might have been there. */
        InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
    }
461

462 463
    p_vout->p_sys->hwnd = NULL;

464 465 466 467 468 469
    /* 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 */
}

/*****************************************************************************
470
 * DirectXUpdateRects: update clipping rectangles
471
 *****************************************************************************
472
 * This function is called when the window position or size are changed, and
473 474 475
 * its job is to update the source and destination RECTs used to display the
 * picture.
 *****************************************************************************/
476
void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
477 478 479 480 481 482
{
#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

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
    int i_width, i_height, i_x, i_y;

    RECT  rect;
    POINT point;

    /* Retrieve the window size */
    GetClientRect( p_vout->p_sys->hwnd, &rect );

    /* Retrieve the window position */
    point.x = point.y = 0;
    ClientToScreen( p_vout->p_sys->hwnd, &point );

    /* If nothing changed, we can return */
    if( !b_force
         && p_vout->p_sys->i_window_width == rect.right
         && p_vout->p_sys->i_window_height == rect.bottom
         && p_vout->p_sys->i_window_x == point.x
         && p_vout->p_sys->i_window_y == point.y )
    {
        return;
    }

    /* Update the window position and size */
    p_vout->p_sys->i_window_x = point.x;
    p_vout->p_sys->i_window_y = point.y;
    p_vout->p_sys->i_window_width = rect.right;
    p_vout->p_sys->i_window_height = rect.bottom;

    vout_PlacePicture( p_vout, rect.right, rect.bottom,
512 513 514
                       &i_x, &i_y, &i_width, &i_height );

    /* Destination image position and dimensions */
515
    rect_dest.left = point.x + i_x;
516
    rect_dest.right = rect_dest.left + i_width;
517
    rect_dest.top = point.y + i_y;
518 519 520 521
    rect_dest.bottom = rect_dest.top + i_height;


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

    /* Clip the destination window */
525 526 527
    IntersectRect( &rect_dest_clipped,
                   &rect_dest,
                   &p_vout->p_sys->rect_display );
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

#if 0
    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 );
#endif

    /* 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);
553
    rect_src_clipped.right = p_vout->render.i_width -
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
      (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);

#if 0
    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 );
#endif

569 570 571 572 573 574 575 576 577 578 579 580 581
    /* Signal the size change */
    if( !p_vout->p_sys->p_event->b_die )
    {
        if( p_vout->p_sys->b_using_overlay )
        {
            DirectXUpdateOverlay( p_vout );
        }
        else
        {
            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
        }
    }

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
}

/*****************************************************************************
 * 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
 * (using the GetMessage and DispatchMessage functions).
 * Nonqueued Messages are those that Windows will send directly to this
 * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
 *****************************************************************************/
static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
                                         WPARAM wParam, LPARAM lParam )
{
602
    vout_thread_t *p_vout;
603

604 605 606 607
    if( message == WM_CREATE )
    {
        /* Store p_vout for future use */
        p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
ipkiss's avatar
ipkiss committed
608
        SetWindowLong( hwnd, GWL_USERDATA, (LONG)p_vout );
609 610
    }
    else
611
    {
ipkiss's avatar
ipkiss committed
612
        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
613 614
    }

615 616 617 618
    switch( message )
    {

    case WM_WINDOWPOSCHANGED:
619
        DirectXUpdateRects( p_vout, VLC_TRUE );
620 621 622 623
        return 0;

    /* the user wants to close the window */
    case WM_CLOSE:
624 625 626 627 628 629
    {
        playlist_t * p_playlist =
            (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
        if( p_playlist == NULL )
        {
630
            return 0;
631 632 633 634
        }

        playlist_Stop( p_playlist );
        vlc_object_release( p_playlist );
635
        return 0;
636
    }
637 638 639 640 641 642 643 644 645 646 647 648 649

    /* 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 );
        return 0;

    case WM_SYSCOMMAND:
        switch (wParam)
        {
            case SC_SCREENSAVE:                     /* catch the screensaver */
            case SC_MONITORPOWER:              /* catch the monitor turn-off */
650 651 652 653
                msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" );
                return 0;                  /* this stops them from happening */
            case IDM_TOGGLE_ON_TOP:            /* toggle the "on top" status */
            {
654
                vlc_value_t val;
655 656
                msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");

657 658 659 660 661 662
                /* Get the current value... */
                if( var_Get( p_vout, "directx-on-top", &val ) < 0 )
                    return 0;
                /* ...and change it */
                val.b_bool = !val.b_bool;
                var_Set( p_vout, "directx-on-top", val );
663 664 665
                return 0;
                break;
            }
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
        }
        break;

    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
            msg_Dbg( p_vout, "WinProc WM_ERASEBKGND %i,%i,%i,%i",
                          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;

    default:
        //msg_Dbg( p_vout, "WinProc WM Default %i", message );
        break;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740

static struct
{
    int i_dxkey;
    int i_vlckey;

} dxkeys_to_vlckeys[] =
{
    { VK_F1, KEY_F1 }, { VK_F2, KEY_F2 }, { VK_F3, KEY_F3 }, { VK_F4, KEY_F4 },
    { VK_F5, KEY_F5 }, { VK_F6, KEY_F6 }, { VK_F7, KEY_F7 }, { VK_F8, KEY_F8 },
    { VK_F9, KEY_F9 }, { VK_F10, KEY_F10 }, { VK_F11, KEY_F11 },
    { VK_F12, KEY_F12 },

    { VK_RETURN, KEY_ENTER },
    { VK_SPACE, KEY_SPACE },
    { VK_ESCAPE, KEY_ESC },

    { VK_MENU, KEY_MENU },
    { VK_LEFT, KEY_LEFT },
    { VK_RIGHT, KEY_RIGHT },
    { VK_UP, KEY_UP },
    { VK_DOWN, KEY_DOWN },

    { VK_HOME, KEY_HOME },
    { VK_END, KEY_END },
    { VK_PRIOR, KEY_PAGEUP },
    { VK_NEXT, KEY_PAGEDOWN },
    { 0, 0 }
};

static int DirectXConvertKey( int i_key )
{
    int i;

    for( i = 0; dxkeys_to_vlckeys[i].i_dxkey != 0; i++ )
    {
        if( dxkeys_to_vlckeys[i].i_dxkey == i_key )
        {
            return dxkeys_to_vlckeys[i].i_vlckey;
        }
    }

    return 0;
}