win32_fullscreen.cpp 36.7 KB
Newer Older
1 2 3
/*****************************************************************************
 * vlc_win32_fullscreen.h: a VLC plugin for Mozilla
 *****************************************************************************
4
 * Copyright © 2002-2011 VideoLAN and VLC authors
5 6 7 8
 * $Id$
 *
 * Authors: Sergey Radionov <rsatom@gmail.com>
 *
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15 16
 * (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
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20 21 22
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
23 24 25
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
26 27 28 29 30

#include <windows.h>
#include <commctrl.h>
#include <uxtheme.h>

31
#include "win32_fullscreen.h"
32

33 34 35 36 37 38
////////////////////////////////////////////////////////////////////////////////
//VLCControlsWnd members
////////////////////////////////////////////////////////////////////////////////
VLCControlsWnd*
VLCControlsWnd::CreateControlsWindow(HINSTANCE hInstance,
                                     VLCWindowsManager* wm, HWND hWndParent)
39
{
40 41 42
    VLCControlsWnd* wnd = new VLCControlsWnd(hInstance, wm);
    if( wnd && wnd->Create(hWndParent) ) {
        return wnd;
43
    }
44
    delete wnd;
45 46 47
    return 0;
}

48 49 50 51
VLCControlsWnd::VLCControlsWnd(HINSTANCE hInstance, VLCWindowsManager* wm)
    :VLCWnd(hInstance), _wm(wm),
     hToolTipWnd(0), hFSButton(0), hPlayPauseButton(0),
     hVideoPosScroll(0), hMuteButton(0), hVolumeSlider(0)
52
{
53 54
}

55
VLCControlsWnd::~VLCControlsWnd()
56
{
57 58 59
    if(hToolTipWnd){
        ::DestroyWindow(hToolTipWnd);
        hToolTipWnd = 0;
60 61 62
    }
}

63
bool VLCControlsWnd::Create(HWND hWndParent)
64
{
65 66 67
    return VLCWnd::CreateEx(WS_EX_TOPMOST, TEXT("VLC Controls Window"),
                            WS_CHILD|WS_CLIPSIBLINGS,
                            0, 0, 0, 0, hWndParent, 0);
68 69
}

70
void VLCControlsWnd::PreRegisterWindowClass(WNDCLASS* wc)
71
{
72 73 74
    wc->lpszClassName = TEXT("VLC Controls Class");
    wc->hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
};
75

76
void VLCControlsWnd::CreateToolTip()
77
{
78 79 80 81 82 83 84 85 86 87 88 89
    hToolTipWnd = CreateWindowEx(WS_EX_TOPMOST,
            TOOLTIPS_CLASS,
            NULL,
            WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            hWnd(),
            NULL,
            hInstance(),
            NULL);
90

91 92 93 94
    SetWindowPos(hToolTipWnd,
            HWND_TOPMOST,
            0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
95 96


97 98 99 100 101
    TOOLINFO ti;
    ti.cbSize = sizeof(TOOLINFO);
    ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
    ti.hwnd   = hWnd();
    ti.hinst  = hInstance();
102

103 104
    TCHAR HintText[100];
    RECT ActivateTTRect;
105

106 107 108 109 110 111 112
    //end fullscreen button tooltip
    GetWindowRect(hFSButton, &ActivateTTRect);
    GetWindowText(hFSButton, HintText, sizeof(HintText));
    ti.uId = (UINT_PTR)hFSButton;
    ti.rect = ActivateTTRect;
    ti.lpszText = HintText;
    SendMessage(hToolTipWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
113

114 115 116 117 118 119 120
    //play/pause button tooltip
    GetWindowRect(hPlayPauseButton, &ActivateTTRect);
    GetWindowText(hPlayPauseButton, HintText, sizeof(HintText));
    ti.uId = (UINT_PTR)hPlayPauseButton;
    ti.rect = ActivateTTRect;
    ti.lpszText = HintText;
    SendMessage(hToolTipWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
121

122 123 124 125 126 127 128
    //mute button tooltip
    GetWindowRect(hMuteButton, &ActivateTTRect);
    GetWindowText(hMuteButton, HintText, sizeof(HintText));
    ti.uId = (UINT_PTR)hMuteButton;
    ti.rect = ActivateTTRect;
    ti.lpszText = HintText;
    SendMessage(hToolTipWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
129 130
}

131
LRESULT VLCControlsWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
132
{
133
    switch(uMsg){
134
        case WM_CREATE:{
135
            const int ControlsHeight = 21+3;
Cheng Sun's avatar
Cheng Sun committed
136
            const int ButtonsWidth = ControlsHeight;
137

138
            int HorizontalOffset = xControlsSpace;
139
            int ControlWidth = ButtonsWidth;
140 141 142 143 144 145 146 147 148
            hPlayPauseButton =
                CreateWindow(TEXT("BUTTON"), TEXT("Play/Pause"),
                             WS_CHILD|WS_VISIBLE|BS_BITMAP|BS_FLAT,
                             HorizontalOffset, xControlsSpace,
                             ControlWidth, ControlsHeight, hWnd(),
                             (HMENU)ID_FS_PLAY_PAUSE, 0, 0);
            SendMessage(hPlayPauseButton, BM_SETIMAGE,
                        (WPARAM)IMAGE_BITMAP, (LPARAM)RC().hPauseBitmap);
            HorizontalOffset+=ControlWidth+xControlsSpace;
149 150

            ControlWidth = 200;
151 152 153 154 155 156 157
            int VideoPosControlHeight = 10;
            hVideoPosScroll =
                CreateWindow(PROGRESS_CLASS, TEXT("Video Position"),
                             WS_CHILD|WS_DISABLED|WS_VISIBLE|SBS_HORZ|SBS_TOPALIGN|PBS_SMOOTH,
                             HorizontalOffset, xControlsSpace+(ControlsHeight-VideoPosControlHeight)/2,
                             ControlWidth, VideoPosControlHeight, hWnd(),
                             (HMENU)ID_FS_VIDEO_POS_SCROLL, 0, 0);
158 159 160 161 162
            HMODULE hThModule = LoadLibrary(TEXT("UxTheme.dll"));
            if(hThModule){
                FARPROC proc = GetProcAddress(hThModule, "SetWindowTheme");
                typedef HRESULT (WINAPI* SetWindowThemeProc)(HWND, LPCWSTR, LPCWSTR);
                if(proc){
163
                    ((SetWindowThemeProc)proc)(hVideoPosScroll, L"", L"");
164 165 166
                }
                FreeLibrary(hThModule);
            }
167
            HorizontalOffset+=ControlWidth+xControlsSpace;
168 169

            ControlWidth = ButtonsWidth;
170 171 172 173 174 175 176 177 178
            hMuteButton =
                CreateWindow(TEXT("BUTTON"), TEXT("Mute"),
                             WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX|BS_PUSHLIKE|BS_BITMAP, //BS_FLAT
                             HorizontalOffset, xControlsSpace,
                             ControlWidth, ControlsHeight,
                             hWnd(), (HMENU)ID_FS_MUTE, 0, 0);
            SendMessage(hMuteButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP,
                        (LPARAM)RC().hVolumeBitmap);
            HorizontalOffset+=ControlWidth+xControlsSpace;
179 180

            ControlWidth = 100;
181 182 183 184 185 186 187 188 189 190 191
            hVolumeSlider =
                CreateWindow(TRACKBAR_CLASS, TEXT("Volume"),
                             WS_CHILD|WS_VISIBLE|TBS_HORZ|TBS_BOTTOM|TBS_AUTOTICKS,
                             HorizontalOffset, xControlsSpace,
                             ControlWidth, ControlsHeight - 4, hWnd(),
                             (HMENU)ID_FS_VOLUME, 0, 0);
            HorizontalOffset+=ControlWidth+xControlsSpace;
            SendMessage(hVolumeSlider, TBM_SETRANGE, FALSE, (LPARAM) MAKELONG (0, 100));
            SendMessage(hVolumeSlider, TBM_SETTICFREQ, (WPARAM) 10, 0);

            ControlWidth = ButtonsWidth;
192 193 194 195
            DWORD dwFSBtnStyle = WS_CHILD|BS_BITMAP|BS_FLAT;
            if( !PO() || PO()->get_enable_fs() ){
                dwFSBtnStyle |= WS_VISIBLE;
            }
196 197
            hFSButton =
                CreateWindow(TEXT("BUTTON"), TEXT("Toggle fullscreen"),
198
                             dwFSBtnStyle,
199 200 201 202 203 204 205 206 207
                             HorizontalOffset, xControlsSpace,
                             ControlWidth, ControlsHeight, hWnd(),
                             (HMENU)ID_FS_SWITCH_FS, 0, 0);
            SendMessage(hFSButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP,
                        (LPARAM)RC().hDeFullscreenBitmap);
            HorizontalOffset+=ControlWidth+xControlsSpace;

            RECT rect;
            GetClientRect(GetParent(hWnd()), &rect);
208 209

            int ControlWndWidth = HorizontalOffset;
210 211 212 213 214
            int ControlWndHeight = xControlsSpace+ControlsHeight+xControlsSpace;
            SetWindowPos(hWnd(), 0,
                         0, (rect.bottom - rect.top) - ControlWndWidth,
                         rect.right-rect.left, ControlWndHeight,
                         SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOACTIVATE);
215 216

            //new message blinking timer
217
            SetTimer(hWnd(), 2, 500, NULL);
218

219
            CreateToolTip();
220 221 222

            break;
        }
223 224 225 226 227 228
        case WM_SHOWWINDOW:{
            if(FALSE!=wParam){ //showing
                UpdateButtons();
            }
            break;
        }
229 230 231
        case WM_LBUTTONUP:{
            POINT BtnUpPoint = {LOWORD(lParam), HIWORD(lParam)};
            RECT VideoPosRect;
232 233
            GetWindowRect(hVideoPosScroll, &VideoPosRect);
            ClientToScreen(hWnd(), &BtnUpPoint);
234
            if(PtInRect(&VideoPosRect, BtnUpPoint)){
235
                SetVideoPos(float(BtnUpPoint.x-VideoPosRect.left)/(VideoPosRect.right-VideoPosRect.left));
236 237 238 239 240 241 242 243 244
            }
            break;
        }
        case WM_TIMER:{
            switch(wParam){
                case 1:{
                    POINT MousePoint;
                    GetCursorPos(&MousePoint);
                    RECT ControlWndRect;
245 246
                    GetWindowRect(hWnd(), &ControlWndRect);
                    if(PtInRect(&ControlWndRect, MousePoint)||GetCapture()==hVolumeSlider){
Cheng Sun's avatar
Cheng Sun committed
247
                        //do not allow control window to close while mouse is within
248
                        NeedShowControls();
249 250
                    }
                    else{
251
                        NeedHideControls();
252 253 254 255
                    }
                    break;
                }
                case 2:{
256
                    UpdateButtons();
257 258 259 260 261 262 263
                    break;
                }
            }
            break;
        }
        case WM_SETCURSOR:{
            RECT VideoPosRect;
264
            GetWindowRect(hVideoPosScroll, &VideoPosRect);
265 266 267 268 269 270 271
            DWORD dwMsgPos = GetMessagePos();
            POINT MsgPosPoint = {LOWORD(dwMsgPos), HIWORD(dwMsgPos)};
            if(PtInRect(&VideoPosRect, MsgPosPoint)){
                SetCursor(LoadCursor(NULL, IDC_HAND));
                return TRUE;
            }
            else{
272
                return VLCWnd::WindowProc(uMsg, wParam, lParam);
273 274 275 276 277 278 279 280 281 282 283 284
            }
            break;
        }
        case WM_NCDESTROY:
            break;
        case WM_COMMAND:{
            WORD NCode = HIWORD(wParam);
            WORD Control = LOWORD(wParam);
            switch(NCode){
                case BN_CLICKED:{
                    switch(Control){
                        case ID_FS_SWITCH_FS:
285
                            WM().ToggleFullScreen();
286 287
                            break;
                        case ID_FS_PLAY_PAUSE:{
288
                            if( VP() ){
289
                                if( IsPlaying() )
290
                                    VP()->pause();
291
                                else
292
                                    VP()->play();
293 294 295 296
                            }
                            break;
                        }
                        case ID_FS_MUTE:{
297 298
                            if( VP() ){
                                VP()->set_mute( IsDlgButtonChecked(hWnd(), ID_FS_MUTE) != FALSE );
299
                                SyncVolumeSliderWithVLCVolume();
300 301 302 303 304 305 306 307 308
                            }
                            break;
                        }
                    }
                    break;
                }
            }
            break;
        }
309
        case WM_SIZE:{
310 311 312 313 314 315 316 317
            if( GetWindowLong(hWnd(), GWL_STYLE) & WS_VISIBLE &&
                !WM().IsFullScreen() &&
                ( !PO() || !PO()->get_show_toolbar() ) )
            {
                //hide controls when they are not allowed
                NeedHideControls();
            }

318 319
            const int new_client_width = LOWORD(lParam);

320 321 322
            bool isFSBtnVisible =
                (GetWindowLong(hFSButton, GWL_STYLE) & WS_VISIBLE) != 0;

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
            HDWP hDwp = BeginDeferWindowPos(4);

            int VideoScrollWidth = new_client_width;

            POINT pt = {0, 0};
            RECT rect;
            GetWindowRect(hPlayPauseButton, &rect);
            pt.x = rect.right;
            ScreenToClient(hWnd(), &pt);
            VideoScrollWidth -= pt.x;
            VideoScrollWidth -= xControlsSpace;

            RECT VideoSrcollRect;
            GetWindowRect(hVideoPosScroll, &VideoSrcollRect);

            RECT MuteRect;
            GetWindowRect(hMuteButton, &MuteRect);
            VideoScrollWidth -= xControlsSpace;
            VideoScrollWidth -= (MuteRect.right - MuteRect.left);

            RECT VolumeRect;
            GetWindowRect(hVolumeSlider, &VolumeRect);
            VideoScrollWidth -= xControlsSpace;
            VideoScrollWidth -= (VolumeRect.right - VolumeRect.left);

348 349 350 351 352 353 354
            RECT FSRect = {0, 0, 0, 0};
            if( isFSBtnVisible ) {
                GetWindowRect(hFSButton, &FSRect);
                VideoScrollWidth -= xControlsSpace;
                VideoScrollWidth -= (FSRect.right - FSRect.left);
                VideoScrollWidth -= xControlsSpace;
            }
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383

            pt.x = VideoSrcollRect.left;
            pt.y = VideoSrcollRect.top;
            ScreenToClient(hWnd(), &pt);
            hDwp = DeferWindowPos(hDwp, hVideoPosScroll, 0, pt.x, pt.y,
                                  VideoScrollWidth,
                                  VideoSrcollRect.bottom - VideoSrcollRect.top,
                                  SWP_NOACTIVATE|SWP_NOOWNERZORDER);

            int HorizontalOffset =
                pt.x + VideoScrollWidth + xControlsSpace;
            pt.x = 0;
            pt.y = MuteRect.top;
            ScreenToClient(hWnd(), &pt);
            hDwp = DeferWindowPos(hDwp, hMuteButton, 0,
                                  HorizontalOffset, pt.y, 0, 0,
                                  SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
            HorizontalOffset +=
                MuteRect.right - MuteRect.left + xControlsSpace;

            pt.x = 0;
            pt.y = VolumeRect.top;
            ScreenToClient(hWnd(), &pt);
            hDwp = DeferWindowPos(hDwp, hVolumeSlider, 0,
                                  HorizontalOffset, pt.y, 0, 0,
                                  SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
            HorizontalOffset +=
                VolumeRect.right - VolumeRect.left + xControlsSpace;

384 385 386 387 388 389 390 391
            if( isFSBtnVisible ) {
                pt.x = 0;
                pt.y = FSRect.top;
                ScreenToClient(hWnd(), &pt);
                hDwp = DeferWindowPos(hDwp, hFSButton, 0,
                                      HorizontalOffset, pt.y, 0, 0,
                                      SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
            }
392 393 394 395

            EndDeferWindowPos(hDwp);
            break;
        }
396 397
        case WM_HSCROLL:
        case WM_VSCROLL: {
398
            if( VP() ){
399 400 401
                if(hVolumeSlider==(HWND)lParam){
                    LRESULT SliderPos = SendMessage(hVolumeSlider, (UINT) TBM_GETPOS, 0, 0);
                    SetVLCVolumeBySliderPos(SliderPos);
402 403 404 405 406
                }
            }
            break;
        }
        default:
407
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
408 409
    }
    return 0L;
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
}

void VLCControlsWnd::UpdateButtons()
{
    if(hVideoPosScroll){
        SetVideoPosScrollRangeByVideoLen();
        SyncVideoPosScrollPosWithVideoPos();
    }

    if(hVolumeSlider){
        SyncVolumeSliderWithVLCVolume();
    }

    if(hFSButton) {
        HANDLE hFSBitmap =
            WM().IsFullScreen() ? RC().hDeFullscreenBitmap :
                                  RC().hFullscreenBitmap;

        HANDLE hBitmap =
            (HANDLE)SendMessage(hFSButton, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);

        if( WM().getNewMessageFlag() &&
           (hBitmap == RC().hDeFullscreenBitmap ||
            hBitmap == RC().hFullscreenBitmap) )
        {
            SendMessage(hFSButton, BM_SETIMAGE,
                        (WPARAM)IMAGE_BITMAP,
                        (LPARAM)RC().hNewMessageBitmap);
            //do not allow control window to close while there are new messages
            NeedShowControls();
        }
        else{
            if(hBitmap != hFSBitmap)
                SendMessage(hFSButton, BM_SETIMAGE,
                            (WPARAM)IMAGE_BITMAP,
                            (LPARAM)hFSBitmap);
        }
    }

    if(hPlayPauseButton){
        HANDLE hBmp = IsPlaying() ? RC().hPauseBitmap : RC().hPlayBitmap;
        SendMessage(hPlayPauseButton, BM_SETIMAGE,
                    (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
    }

}

void VLCControlsWnd::NeedShowControls()
{
459
    if( !(GetWindowLong(hWnd(), GWL_STYLE) & WS_VISIBLE) ) {
460 461
        if(WM().IsFullScreen() || (PO() && PO()->get_show_toolbar() ) )
            ShowWindow( hWnd(), SW_SHOW );
462 463 464 465 466 467 468 469 470 471 472 473 474
    }
    //hide controls after 2 seconds
    SetTimer(hWnd(), 1, 2*1000, NULL);
}

void VLCControlsWnd::NeedHideControls()
{
    KillTimer( hWnd(), 1 );
    ShowWindow( hWnd(), SW_HIDE );
}

void VLCControlsWnd::SyncVideoPosScrollPosWithVideoPos()
{
475 476
    if( VP() ){
        libvlc_time_t pos = VP()->get_time();
477 478 479 480 481 482
        SetVideoPosScrollPosByVideoPos(pos);
    }
}

void VLCControlsWnd::SetVideoPosScrollRangeByVideoLen()
{
483 484
    if( VP() ){
        libvlc_time_t MaxLen = VP()->get_length();
485 486 487 488 489 490 491 492 493 494 495
        VideoPosShiftBits = 0;
        while(MaxLen>0xffff){
            MaxLen >>= 1;
            ++VideoPosShiftBits;
        };
        SendMessage(hVideoPosScroll, (UINT)PBM_SETRANGE, 0, MAKELPARAM(0, MaxLen));
    }
}

void VLCControlsWnd::SetVideoPosScrollPosByVideoPos(libvlc_time_t CurScrollPos)
{
496
    PostMessage(hVideoPosScroll, (UINT)PBM_SETPOS, (WPARAM) (CurScrollPos >> VideoPosShiftBits), 0);
497 498 499 500
}

void VLCControlsWnd::SetVideoPos(float Pos) //0-start, 1-end
{
501 502 503
    if( VP() ){
        vlc_player& vp = *VP();
        vp.set_time( static_cast<libvlc_time_t>( vp.get_length()*Pos ) );
504 505 506 507 508 509
        SyncVideoPosScrollPosWithVideoPos();
    }
}

void VLCControlsWnd::SyncVolumeSliderWithVLCVolume()
{
510 511 512
    if( VP() ){
        vlc_player& vp = *VP();
        unsigned int vol = vp.get_volume();
513
        const LRESULT SliderPos = SendMessage(hVolumeSlider, (UINT) TBM_GETPOS, 0, 0);
514
        if((UINT)SliderPos!=vol)
515 516
            SendMessage(hVolumeSlider, (UINT) TBM_SETPOS, (WPARAM) TRUE, (LPARAM) vol);

517
        bool muted = vp.is_muted();
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
        int MuteButtonState = SendMessage(hMuteButton, (UINT) BM_GETCHECK, 0, 0);
        if((muted&&(BST_UNCHECKED==MuteButtonState))||(!muted&&(BST_CHECKED==MuteButtonState))){
            SendMessage(hMuteButton, BM_SETCHECK, (WPARAM)(muted?BST_CHECKED:BST_UNCHECKED), 0);
        }
        LRESULT lResult = SendMessage(hMuteButton, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
        if( (muted && ((HANDLE)lResult == RC().hVolumeBitmap)) ||
            (!muted&&((HANDLE)lResult == RC().hVolumeMutedBitmap)) )
        {
            HANDLE hBmp = muted ? RC().hVolumeMutedBitmap : RC().hVolumeBitmap ;
            SendMessage(hMuteButton, BM_SETIMAGE,
                        (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
        }
    }
}

void VLCControlsWnd::SetVLCVolumeBySliderPos(int CurPos)
{
535 536 537
    if( VP() ){
        vlc_player& vp = *VP();
        vp.set_volume(CurPos);
538
        if(0==CurPos){
539
            vp.set_mute( IsDlgButtonChecked( hWnd(), ID_FS_MUTE) != FALSE );
540 541 542 543 544 545 546 547 548
        }
        SyncVolumeSliderWithVLCVolume();
    }
}


/////////////////////////////////////
//VLCControlsWnd event handlers

549
void VLCControlsWnd::handle_position_changed_event(const libvlc_event_t* )
550 551 552 553 554 555 556 557 558
{
    SyncVideoPosScrollPosWithVideoPos();
}

void VLCControlsWnd::handle_input_state_event(const libvlc_event_t* event)
{
    switch( event->type )
    {
        case libvlc_MediaPlayerPlaying:
559
            PostMessage(hPlayPauseButton, BM_SETIMAGE,
560 561 562
                        (WPARAM)IMAGE_BITMAP, (LPARAM)RC().hPauseBitmap);
            break;
        case libvlc_MediaPlayerPaused:
563
            PostMessage(hPlayPauseButton, BM_SETIMAGE,
564 565 566
                        (WPARAM)IMAGE_BITMAP, (LPARAM)RC().hPlayBitmap);
            break;
        case libvlc_MediaPlayerStopped:
567
            PostMessage(hPlayPauseButton, BM_SETIMAGE,
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
                        (WPARAM)IMAGE_BITMAP, (LPARAM)RC().hPlayBitmap);
            break;
    }
}

//libvlc events arrives from separate thread
void VLCControlsWnd::OnLibVlcEvent(const libvlc_event_t* event)
{
    switch(event->type){
        case libvlc_MediaPlayerPlaying:
        case libvlc_MediaPlayerPaused:
        case libvlc_MediaPlayerStopped:
            handle_input_state_event(event);
            break;
        case libvlc_MediaPlayerPositionChanged:
            handle_position_changed_event(event);
            break;
    }
}

588 589 590
////////////////////////////////////////////////////////////////////////////////
//VLCHolderWnd members
////////////////////////////////////////////////////////////////////////////////
591 592 593 594
enum{
    WM_TRY_SET_MOUSE_HOOK = WM_USER+1,
    WM_MOUSE_EVENT_NOTIFY = WM_APP+1,
    WM_MOUSE_EVENT_NOTIFY_SUCCESS = 0xFF
595 596
};

597 598 599
VLCHolderWnd*
VLCHolderWnd::CreateHolderWindow(HINSTANCE hInstance,
                                 HWND hParentWnd, VLCWindowsManager* WM)
600
{
601 602 603
    VLCHolderWnd* wnd = new VLCHolderWnd(hInstance, WM);
    if( wnd && wnd->Create(hParentWnd) ) {
        return wnd;
604
    }
605 606
    delete wnd;
    return 0;
607 608
}

609
VLCHolderWnd::~VLCHolderWnd()
610
{
611 612 613 614
    if(_hBgBrush) {
        DeleteObject(_hBgBrush);
        _hBgBrush = 0;
    }
615 616
}

617
bool VLCHolderWnd::Create(HWND hWndParent)
618
{
619 620 621
    return VLCWnd::Create(TEXT("Holder Window"),
                            WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_VISIBLE,
                            0, 0, 0, 0, hWndParent, 0);
622 623
}

624
void VLCHolderWnd::PreRegisterWindowClass(WNDCLASS* wc)
625
{
626
    if( !_hBgBrush){
627
        unsigned r = 0, g = 0, b = 0;
628
        HTMLColor2RGB(PO()->get_bg_color().c_str(), &r, &g, &b);
629 630 631 632
        _hBgBrush = CreateSolidBrush(RGB(r, g, b));
    }

    wc->hbrBackground = _hBgBrush;
633 634
    wc->lpszClassName = TEXT("Web Plugin VLC Window Holder Class");
}
635

636 637
LRESULT VLCHolderWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
638 639 640 641 642 643 644
    switch( uMsg )
    {
        case WM_CREATE:{
            CREATESTRUCT* CreateStruct = (CREATESTRUCT*)(lParam);

            RECT ParentClientRect;
            GetClientRect(CreateStruct->hwndParent, &ParentClientRect);
645
            MoveWindow(hWnd(), 0, 0,
646 647
                       (ParentClientRect.right-ParentClientRect.left),
                       (ParentClientRect.bottom-ParentClientRect.top), FALSE);
648 649 650
            _CtrlsWnd =
                VLCControlsWnd::CreateControlsWindow(hInstance(), _wm,
                                                     hWnd());
651 652 653 654
            break;
        }
        case WM_PAINT:{
            PAINTSTRUCT PaintStruct;
655
            HDC hDC = BeginPaint(hWnd(), &PaintStruct);
656
            RECT rect;
657
            GetClientRect(hWnd(), &rect);
658 659
            int IconX = ((rect.right - rect.left) - GetSystemMetrics(SM_CXICON))/2;
            int IconY = ((rect.bottom - rect.top) - GetSystemMetrics(SM_CYICON))/2;
660 661
            DrawIcon(hDC, IconX, IconY, RC().hBackgroundIcon);
            EndPaint(hWnd(), &PaintStruct);
662 663
            break;
        }
664 665
        case WM_SHOWWINDOW:{
            if(FALSE!=wParam){ //showing
666
                NeedShowControls();
667 668 669
            }
            break;
        }
670
        case WM_TRY_SET_MOUSE_HOOK:{
671
            MouseHook(true);
672 673
            break;
        }
674
        case WM_SIZE:
675
            if(_CtrlsWnd){
676 677 678 679
                int new_client_width = LOWORD(lParam);
                int new_client_height = HIWORD(lParam);

                RECT rect;
680
                GetWindowRect(_CtrlsWnd->hWnd(), &rect);
681

682
                MoveWindow(_CtrlsWnd->hWnd(),
683 684 685 686
                           0, new_client_height - (rect.bottom - rect.top),
                           new_client_width, (rect.bottom-rect.top), TRUE);
            }
            break;
687 688
        case WM_MOUSEMOVE:
        case WM_LBUTTONDBLCLK:
689
            WM().OnMouseEvent(uMsg);
690 691
            break;
        case WM_MOUSE_EVENT_NOTIFY:{
692
            WM().OnMouseEvent(wParam);
693 694 695
            return WM_MOUSE_EVENT_NOTIFY_SUCCESS;
        }
        default:
696
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
697 698
    }
    return 0;
699
}
700 701 702 703

void VLCHolderWnd::DestroyWindow()
{
    LibVlcDetach();
704 705 706 707 708 709

    if(_CtrlsWnd){
        delete _CtrlsWnd;
        _CtrlsWnd = 0;
    }

710 711
    if(hWnd())
        ::DestroyWindow(hWnd());
712 713 714
};

LRESULT CALLBACK VLCHolderWnd::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
715
{
716 717 718 719 720 721
    bool AllowReceiveMessage = true;
    if(nCode >= 0){
        switch(wParam){
            case WM_MOUSEMOVE:
            case WM_LBUTTONDBLCLK:{
                MOUSEHOOKSTRUCT* mhs = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
722

723 724 725 726 727 728 729 730 731 732
                //try to find HolderWnd and notify it
                HWND hNotifyWnd = mhs->hwnd;
                LRESULT SMRes = ::SendMessage(hNotifyWnd, WM_MOUSE_EVENT_NOTIFY, wParam, 0);
                while( hNotifyWnd && WM_MOUSE_EVENT_NOTIFY_SUCCESS != SMRes){
                    hNotifyWnd = GetParent(hNotifyWnd);
                    SMRes = ::SendMessage(hNotifyWnd, WM_MOUSE_EVENT_NOTIFY, wParam, 0);
                }

                AllowReceiveMessage = WM_MOUSEMOVE==wParam || (WM_MOUSE_EVENT_NOTIFY_SUCCESS != SMRes);
                break;
733 734 735 736
            }
        }
    }

737 738 739 740 741
    LRESULT NHRes = CallNextHookEx(NULL, nCode, wParam, lParam);
    if(AllowReceiveMessage)
        return NHRes;
    else
        return 1;
742 743
}

744
void VLCHolderWnd::MouseHook(bool SetHook)
745
{
746
    if(SetHook){
747 748 749
        HWND hMPWnd = FindMP_hWnd();
        const DWORD WndThreadID = (hMPWnd) ? GetWindowThreadProcessId(hMPWnd, NULL) : 0;
        if( _hMouseHook &&( !hMPWnd || WndThreadID != _MouseHookThreadId) ){
750 751 752
            //unhook if something changed
            MouseHook(false);
        }
753

754
        if(!_hMouseHook && hMPWnd && WndThreadID){
755 756 757 758 759 760 761 762 763 764 765 766
            _MouseHookThreadId = WndThreadID;
            _hMouseHook =
                SetWindowsHookEx(WH_MOUSE, VLCHolderWnd::MouseHookProc,
                                 NULL, WndThreadID);
        }
    }
    else{
        if(_hMouseHook){
            UnhookWindowsHookEx(_hMouseHook);
            _MouseHookThreadId=0;
            _hMouseHook = 0;
        }
767 768 769
    }
}

770 771 772 773 774
HWND VLCHolderWnd::FindMP_hWnd()
{
    if(_CtrlsWnd)
        return GetWindow(_CtrlsWnd->hWnd(), GW_HWNDNEXT);
    else
775
        return GetWindow(hWnd(), GW_CHILD);
776 777
}

778 779
//libvlc events arrives from separate thread
void VLCHolderWnd::OnLibVlcEvent(const libvlc_event_t* event)
780
{
781 782 783 784 785 786
    //We need set hook to catch doubleclicking (to switch to fullscreen and vice versa).
    //But libvlc media window may not exist yet,
    //and we don't know when it will be created, nor ThreadId of it.
    //So we try catch events,
    //(suppose wnd will be ever created),
    //and then try set mouse hook.
787 788
    HWND hMPWnd = FindMP_hWnd();
    const DWORD WndThreadID = (hMPWnd) ? GetWindowThreadProcessId(hMPWnd, NULL) : 0;
789
    //if no hook, or window thread has changed
790 791 792 793 794
    if(!_hMouseHook || (hMPWnd && WndThreadID != _MouseHookThreadId)){
        DWORD s = GetWindowLong(hMPWnd, GWL_STYLE);
        s |= WS_CLIPSIBLINGS;
        SetWindowLong(hMPWnd, GWL_STYLE, s);

795 796
        //libvlc events arrives from separate thread,
        //so we need post message to main thread, to notify it.
797
        PostMessage(hWnd(), WM_TRY_SET_MOUSE_HOOK, 0, 0);
798
    }
799 800 801

    if( _CtrlsWnd )
        _CtrlsWnd->OnLibVlcEvent(event);
802 803
}

804
void VLCHolderWnd::LibVlcAttach()
805
{
806 807
    if( VP() )
        libvlc_media_player_set_hwnd( VP()->get_mp(), hWnd() );
808 809
}

810
void VLCHolderWnd::LibVlcDetach()
811
{
812 813
    if( VP() )
        libvlc_media_player_set_hwnd( VP()->get_mp(), 0);
814

815
    MouseHook(false);
816 817
}

818 819 820 821 822
////////////////////////////////////////////////////////////////////////////////
//VLCFullScreenWnd members
////////////////////////////////////////////////////////////////////////////////
HINSTANCE VLCFullScreenWnd::_hinstance = 0;
ATOM VLCFullScreenWnd::_fullscreen_wndclass_atom = 0;
823

824
void VLCFullScreenWnd::RegisterWndClassName(HINSTANCE hInstance)
825
{
826 827
    //save hInstance for future use
    _hinstance = hInstance;
828

829
    WNDCLASS wClass;
830

831 832 833 834 835 836 837 838 839 840 841 842 843
    memset(&wClass, 0 , sizeof(wClass));
    if( ! GetClassInfo(_hinstance,  getClassName(), &wClass) )
    {
        wClass.style          = CS_NOCLOSE|CS_DBLCLKS;
        wClass.lpfnWndProc    = FSWndWindowProc;
        wClass.cbClsExtra     = 0;
        wClass.cbWndExtra     = 0;
        wClass.hInstance      = _hinstance;
        wClass.hIcon          = NULL;
        wClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wClass.hbrBackground  = (HBRUSH)(COLOR_3DFACE+1);
        wClass.lpszMenuName   = NULL;
        wClass.lpszClassName  = getClassName();
844

845 846 847 848 849 850
        _fullscreen_wndclass_atom = RegisterClass(&wClass);
    }
    else
    {
        _fullscreen_wndclass_atom = 0;
    }
851 852

}
853
void VLCFullScreenWnd::UnRegisterWndClassName()
854
{
855 856 857 858
    if(0 != _fullscreen_wndclass_atom){
        UnregisterClass(MAKEINTATOM(_fullscreen_wndclass_atom), _hinstance);
        _fullscreen_wndclass_atom = 0;
    }
859 860
}

861
LRESULT CALLBACK VLCFullScreenWnd::FSWndWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
862
{
863 864 865
    VLCFullScreenWnd* fs_data = reinterpret_cast<VLCFullScreenWnd *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

    switch( uMsg )
866
    {
867 868 869 870 871 872 873
        case WM_CREATE:{
            CREATESTRUCT* CreateStruct = (CREATESTRUCT*)(lParam);
            VLCWindowsManager* WM = (VLCWindowsManager*)CreateStruct->lpCreateParams;

            fs_data = new VLCFullScreenWnd(hWnd, WM);
            SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(fs_data));

874
            break;
875 876 877 878
        }
        case WM_NCDESTROY:
            delete fs_data;
            SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
879
            break;
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
        case WM_SHOWWINDOW:{
            if(FALSE==wParam){ //hiding
                break;
            }

            //simulate lParam for WM_SIZE
            RECT ClientRect;
            GetClientRect(hWnd, &ClientRect);
            lParam = MAKELPARAM(ClientRect.right, ClientRect.bottom);
        }
        case WM_SIZE:{
            if(fs_data->_WindowsManager->IsFullScreen()){
                int new_client_width = LOWORD(lParam);
                int new_client_height = HIWORD(lParam);
                VLCHolderWnd* HolderWnd =  fs_data->_WindowsManager->getHolderWnd();
895 896 897
                SetWindowPos(HolderWnd->hWnd(), HWND_BOTTOM, 0, 0,
                             new_client_width, new_client_height,
                             SWP_NOACTIVATE|SWP_NOOWNERZORDER);
898
            }
899
            break;
900
        }
901 902 903 904 905
        case WM_KEYDOWN: {
            if (fs_data)
                fs_data->_WindowsManager->OnKeyDownEvent(wParam);
            break;
        }
906 907
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
908
    }
909 910
    return 0L;
};
911

912
VLCFullScreenWnd* VLCFullScreenWnd::CreateFSWindow(VLCWindowsManager* WM)
913
{
914 915 916 917 918 919 920 921 922 923 924
    HWND hWnd = CreateWindow(getClassName(),
                TEXT("VLC ActiveX Full Screen Window"),
                WS_POPUP|WS_CLIPCHILDREN,
                0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
                0,
                0,
                VLCFullScreenWnd::_hinstance,
                (LPVOID)WM
                );
    if(hWnd)
        return reinterpret_cast<VLCFullScreenWnd*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
925

926
    return 0;
927 928 929 930 931
}

///////////////////////
//VLCWindowsManager
///////////////////////
932 933
VLCWindowsManager::VLCWindowsManager(HMODULE hModule, const VLCViewResources& rc,
                                     const vlc_player_options* po)
934
    :_rc(rc), _hModule(hModule), _po(po), _hWindowedParentWnd(0), _vp(0),
935
    _HolderWnd(0), _FSWnd(0), _b_new_messages_flag(false), Last_WM_MOUSEMOVE_Pos(0)
936 937 938 939 940 941 942 943 944 945 946 947 948 949
{
    VLCFullScreenWnd::RegisterWndClassName(hModule);
}

VLCWindowsManager::~VLCWindowsManager()
{
    VLCFullScreenWnd::UnRegisterWndClassName();
}

void VLCWindowsManager::CreateWindows(HWND hWindowedParentWnd)
{
    _hWindowedParentWnd = hWindowedParentWnd;

    if(!_HolderWnd){
950 951 952
        _HolderWnd =
            VLCHolderWnd::CreateHolderWindow(getHModule(),
                                             hWindowedParentWnd, this);
953 954 955 956 957
    }
}

void VLCWindowsManager::DestroyWindows()
{
958 959
    if(_HolderWnd){
        _HolderWnd->DestroyWindow();
960 961
        delete _HolderWnd;
        _HolderWnd = 0;
962
    }
963 964 965 966 967

    if(_FSWnd){
        _FSWnd->DestroyWindow();
    }
    _FSWnd = 0;
968 969
}

970
void VLCWindowsManager::LibVlcAttach(vlc_player* vp)
971
{
972 973 974
    if(!_HolderWnd)
        return;//VLCWindowsManager::CreateWindows was not called

975
    if( vp && _vp != vp ){
976 977 978
        LibVlcDetach();
    }

979 980
    if( !_vp ){
        _vp = vp;
981 982 983 984
        VlcEvents(true);
    }

    _HolderWnd->LibVlcAttach();
985 986 987 988
}

void VLCWindowsManager::LibVlcDetach()
{
989 990
    if(_HolderWnd)
        _HolderWnd->LibVlcDetach();
991

992
    if(_vp){
993
        VlcEvents(false);
994
        _vp = 0;
995
    }
996 997 998 999
}

void VLCWindowsManager::StartFullScreen()
{
1000
    if( !_HolderWnd || ( PO() && !PO()->get_enable_fs() ) )
1001 1002
        return;//VLCWindowsManager::CreateWindows was not called

1003 1004
    if( VP() && !IsFullScreen() ){
        if( !_FSWnd ){
1005 1006 1007
            _FSWnd= VLCFullScreenWnd::CreateFSWindow(this);
        }

1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
        RECT FSRect = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };

        HMONITOR hMonitor = MonitorFromWindow(_hWindowedParentWnd, MONITOR_DEFAULTTONEAREST);
        MONITORINFO MonInfo;
        memset(&MonInfo, 0, sizeof(MonInfo));
        MonInfo.cbSize = sizeof(MonInfo);
        if( GetMonitorInfo(hMonitor, &MonInfo) ) {
            FSRect = MonInfo.rcMonitor;
        }

#ifdef _DEBUG
        //to simplify debugging in fullscreen mode
        UINT FSFlags = SWP_NOZORDER;
#else
        UINT FSFlags = 0;
#endif

1025
        SetParent(_HolderWnd->hWnd(), _FSWnd->getHWND());
1026 1027 1028 1029
        SetWindowPos(_FSWnd->getHWND(), HWND_TOPMOST,
                     FSRect.left, FSRect.top,
                     FSRect.right - FSRect.left, FSRect.bottom - FSRect.top,
                     FSFlags);
1030 1031 1032 1033 1034 1035 1036

        ShowWindow(_FSWnd->getHWND(), SW_SHOW);
    }
}

void VLCWindowsManager::EndFullScreen()
{
1037 1038 1039
    if(!_HolderWnd)
        return;//VLCWindowsManager::CreateWindows was not called

1040
    if(IsFullScreen()){
1041
        SetParent(_HolderWnd->hWnd(), _hWindowedParentWnd);
1042 1043 1044

        RECT WindowedParentRect;
        GetClientRect(_hWindowedParentWnd, &WindowedParentRect);
1045 1046
        MoveWindow(_HolderWnd->hWnd(), 0, 0,
                   WindowedParentRect.right, WindowedParentRect.bottom, FALSE);
1047 1048

        ShowWindow(_FSWnd->getHWND(), SW_HIDE);
1049 1050 1051 1052 1053 1054

        if(_FSWnd){
            _FSWnd->DestroyWindow();
        }
        _FSWnd = 0;
   }
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
}

void VLCWindowsManager::ToggleFullScreen()
{
    if(IsFullScreen()){
        EndFullScreen();
    }
    else{
        StartFullScreen();
    }
}

bool VLCWindowsManager::IsFullScreen()
{
1069
    return 0!=_FSWnd && 0!=_HolderWnd && GetParent(_HolderWnd->hWnd())==_FSWnd->getHWND();
1070 1071
}

1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
void VLCWindowsManager::OnKeyDownEvent(UINT uKeyMsg)
{
    switch(uKeyMsg){
        case VK_ESCAPE:
        case 'F':
            EndFullScreen();
            break;
    }
}

1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
void VLCWindowsManager::OnMouseEvent(UINT uMouseMsg)
{
    switch(uMouseMsg){
        case WM_LBUTTONDBLCLK:
            ToggleFullScreen();
            break;
        case WM_MOUSEMOVE:{
            DWORD MsgPos = GetMessagePos();
            if(Last_WM_MOUSEMOVE_Pos != MsgPos){
                Last_WM_MOUSEMOVE_Pos = MsgPos;
1092
                _HolderWnd->NeedShowControls();
1093 1094 1095 1096 1097
            }
            break;
        }
    }
}
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107

//libvlc events arrives from separate thread
void VLCWindowsManager::OnLibVlcEvent_proxy(const libvlc_event_t* event, void *param)
{
    VLCWindowsManager* WM = static_cast<VLCWindowsManager*>(param);
    WM->OnLibVlcEvent(event);
}

void VLCWindowsManager::VlcEvents(bool Attach)
{
1108
    if( !VP() )
1109 1110
        return;

1111 1112
    vlc_player& vp = *VP();

1113
    libvlc_event_manager_t* em =
1114
        libvlc_media_player_event_manager( vp.get_mp() );
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
    if(!em)
        return;

    for(int e=libvlc_MediaPlayerMediaChanged; e<=libvlc_MediaPlayerVout; ++e){
        switch(e){
        //case libvlc_MediaPlayerMediaChanged:
        //case libvlc_MediaPlayerNothingSpecial:
        //case libvlc_MediaPlayerOpening:
        //case libvlc_MediaPlayerBuffering:
        case libvlc_MediaPlayerPlaying:
        case libvlc_MediaPlayerPaused:
        case libvlc_MediaPlayerStopped:
        //case libvlc_MediaPlayerForward:
        //case libvlc_MediaPlayerBackward:
        //case libvlc_MediaPlayerEndReached:
        //case libvlc_MediaPlayerEncounteredError:
        //case libvlc_MediaPlayerTimeChanged:
        case libvlc_MediaPlayerPositionChanged:
        //case libvlc_MediaPlayerSeekableChanged:
        //case libvlc_MediaPlayerPausableChanged:
        //case libvlc_MediaPlayerTitleChanged:
        //case libvlc_MediaPlayerSnapshotTaken:
        //case libvlc_MediaPlayerLengthChanged:
        //case libvlc_MediaPlayerVout:
            if(Attach)
                libvlc_event_attach(em, e, OnLibVlcEvent_proxy, this);
            else
                libvlc_event_detach(em, e, OnLibVlcEvent_proxy, this);
            break;
        }
    }
}

void VLCWindowsManager::OnLibVlcEvent(const libvlc_event_t* event)
{
    if(_HolderWnd) _HolderWnd->OnLibVlcEvent(event);
    if(_FSWnd) _FSWnd->OnLibVlcEvent(event);
}