events.c 25.9 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * events.c: Windows DirectX video output events handler
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: events.c,v 1.29 2003/11/19 23:44:35 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
 *
 * 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() */
31
#include <ctype.h>                                              /* tolower() */
32 33 34 35
#include <string.h>                                            /* strerror() */

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

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

#include <ddraw.h>

45
#include "vlc_keys.h"
46 47 48 49 50 51 52 53 54 55
#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 );

56 57 58 59 60 61 62 63 64 65 66 67 68
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 );
    }
}

69 70
static int DirectXConvertKey( int i_key );

71 72 73 74 75 76 77 78 79 80 81
/*****************************************************************************
 * 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
82
    POINT old_mouse_pos = {0,0};
83 84
    vlc_value_t val;
    int i_width, i_height, i_x, i_y;
85 86 87 88 89

    /* Initialisation */

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

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

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

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

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

        case WM_NCMOUSEMOVE:
        case WM_MOUSEMOVE:
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
            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 );

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
            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
150 151 152 153
        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 );
154
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
            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 );
174
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
175 176 177 178 179 180 181 182 183 184 185 186
            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 );
187
            DirectXPopupMenu( p_event, VLC_FALSE );
gbazin's avatar
 
gbazin committed
188 189
            break;

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

        case WM_KEYDOWN:
gbazin's avatar
 
gbazin committed
198
        case WM_SYSKEYDOWN:
199 200 201 202 203
            /* The key events are first processed here and not translated
             * into WM_CHAR events because we need to know the status of the
             * modifier keys. */
            val.i_int = DirectXConvertKey( msg.wParam );
            if( !val.i_int )
204
            {
205 206
                /* This appears to be a "normal" (ascii) key */
                val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) );
207
            }
208

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

gbazin's avatar
 
gbazin committed
224
                var_Set( p_event->p_vlc, "key-pressed", val );
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
            }
            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 */
    }

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

    /* 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;
    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
    hInstance = GetModuleHandle(NULL);

    /* Get the current size of the display and its colour depth */
278
    hdc = GetDC( NULL );
279 280 281 282 283 284 285 286 287
    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 );

288
    /* If an external window was specified, we'll draw in it. */
289
    var_Get( p_vout->p_vlc, "drawable", &val );
290
    p_vout->p_sys->hparent = p_vout->p_sys->hwnd =
291
             val.i_int ?  (void*)(ptrdiff_t) val.i_int : NULL;
292 293

    if( p_vout->p_sys->hparent )
294
    {
295 296 297 298 299 300 301
        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,
302
                      GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH) );
303 304
        SetClassLong( p_vout->p_sys->hwnd,
                      GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW) );
305 306 307 308
        /* 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 );

309 310 311 312 313 314 315
        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 );
316
    }
317
    else
318
    {
319 320 321
        WNDCLASSEX wc;                            /* window class components */
        HICON      vlc_icon = NULL;
        char       vlc_path[MAX_PATH+1];
322

323 324 325
        /* Get the Icon from the main app */
        vlc_icon = NULL;
        if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
326
        {
327
            vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
328 329
        }

330 331 332 333 334 335 336 337 338
        /* 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 */
339
        wc.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
340 341 342 343 344 345
        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) )
346
        {
347 348 349 350 351 352 353 354 355 356 357 358 359 360
            WNDCLASS wndclass;

            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;
            }
361 362
        }

363 364 365 366 367 368 369 370 371 372 373 374 375
        /* 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 */
376
                    VOUT_TITLE " (DirectX Output)", /* window title bar text */
377 378
                    WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE |
                    WS_CLIPCHILDREN,                         /* window style */
379 380 381 382 383 384 385
                    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 */
386
                    (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
387

388 389 390 391 392
        if( !p_vout->p_sys->hwnd )
        {
            msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
            return VLC_EGENERIC;
        }
393 394
    }

395 396 397 398 399 400 401 402
    /* Now display the window */
    ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );

    /* Create video sub-window. This sub window will always exactly match
     * the size of the video, which allows us to use crazy overlay colorkeys
     * without having them shown outside of the video area. */
    SendMessage( p_vout->p_sys->hwnd, WM_VLC_CREATE_VIDEO_WIN, 0, 0 );

403
    /* Append a "Always On Top" entry in the system menu */
404 405
    hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
    AppendMenu( hMenu, MF_SEPARATOR, 0, "" );
406 407
    AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
                       IDM_TOGGLE_ON_TOP, "Always on &Top" );
408

409
    return VLC_SUCCESS;
410 411 412 413 414 415 416 417 418 419 420
}

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

421
    if( p_vout->p_sys->hwnd && !p_vout->p_sys->hparent )
422 423 424
    {
        DestroyWindow( p_vout->p_sys->hwnd );
    }
425 426 427 428 429 430 431 432 433
    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 );
    }
434

435 436
    p_vout->p_sys->hwnd = NULL;

437 438 439 440 441 442
    /* 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 */
}

/*****************************************************************************
443
 * DirectXUpdateRects: update clipping rectangles
444
 *****************************************************************************
445
 * This function is called when the window position or size are changed, and
446 447 448
 * its job is to update the source and destination RECTs used to display the
 * picture.
 *****************************************************************************/
449
void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
450 451 452 453 454 455
{
#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

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
    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,
485 486
                       &i_x, &i_y, &i_width, &i_height );

487 488 489
    SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
                  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 495 496 497
    rect_dest.bottom = rect_dest.top + i_height;


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

    /* Clip the destination window */
501
    IntersectRect( &rect_dest_clipped, &rect_dest,
502
                   &p_vout->p_sys->rect_display );
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527

#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);
528
    rect_src_clipped.right = p_vout->render.i_width -
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
      (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

544 545 546 547 548 549 550 551 552 553 554 555 556
    /* 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;
        }
    }

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
#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 )
{
577
    vout_thread_t *p_vout;
578

579 580 581 582
    if( message == WM_CREATE )
    {
        /* Store p_vout for future use */
        p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
ipkiss's avatar
ipkiss committed
583
        SetWindowLong( hwnd, GWL_USERDATA, (LONG)p_vout );
584 585
    }
    else
586
    {
ipkiss's avatar
ipkiss committed
587
        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
588 589
    }

590 591 592 593
    switch( message )
    {

    case WM_WINDOWPOSCHANGED:
594
        DirectXUpdateRects( p_vout, VLC_TRUE );
595 596 597 598
        return 0;

    /* the user wants to close the window */
    case WM_CLOSE:
599 600 601 602 603 604
    {
        playlist_t * p_playlist =
            (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
        if( p_playlist == NULL )
        {
605
            return 0;
606 607 608 609
        }

        playlist_Stop( p_playlist );
        vlc_object_release( p_playlist );
610
        return 0;
611
    }
612 613 614 615 616 617 618 619 620 621 622 623 624

    /* 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 */
625 626 627 628
                msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" );
                return 0;                  /* this stops them from happening */
            case IDM_TOGGLE_ON_TOP:            /* toggle the "on top" status */
            {
629
                vlc_value_t val;
630 631
                msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");

632 633 634 635 636 637
                /* 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 );
638 639 640
                return 0;
                break;
            }
641 642 643
        }
        break;

644 645 646 647 648 649 650 651 652 653 654
    case WM_VLC_CREATE_VIDEO_WIN:
        /* Create video sub-window */
        p_vout->p_sys->hvideownd =
            CreateWindow( "STATIC", "",   /* window class and title bar text */
                    WS_CHILD | WS_VISIBLE,                   /* window style */
                    CW_USEDEFAULT, CW_USEDEFAULT,     /* default coordinates */
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    hwnd,                                   /* parent window */
                    NULL, GetModuleHandle(NULL), NULL );

        if( !p_vout->p_sys->hvideownd )
655
        {
656 657 658 659 660 661
            msg_Warn( p_vout, "Can create video sub-window" );
        }
        else
        {
            SetWindowLong( p_vout->p_sys->hvideownd,
                           GWL_WNDPROC, (LONG)DefWindowProc );
662 663 664 665 666 667 668 669 670 671
        }
        break;

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

    return DefWindowProc(hwnd, message, wParam, lParam);
}
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 697

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_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 },
gbazin's avatar
 
gbazin committed
698 699 700 701 702

    { VK_CONTROL, 0 },
    { VK_SHIFT, 0 },
    { VK_MENU, 0 },

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
    { 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;
}