win32_fullscreen.cpp 37.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 26
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
27 28

#include <windows.h>
29
#include <windowsx.h>
30 31
#include <commctrl.h>
#include <uxtheme.h>
32
#include <math.h>
33

34
#include "win32_fullscreen.h"
35

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

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

58
VLCControlsWnd::~VLCControlsWnd()
59
{
60 61 62
    if(hToolTipWnd){
        ::DestroyWindow(hToolTipWnd);
        hToolTipWnd = 0;
63 64 65
    }
}

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

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

79
void VLCControlsWnd::CreateToolTip()
80
{
81 82 83 84 85 86 87 88 89 90 91 92
    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);
93

94 95 96 97
    SetWindowPos(hToolTipWnd,
            HWND_TOPMOST,
            0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
98 99


100 101 102 103 104
    TOOLINFO ti;
    ti.cbSize = sizeof(TOOLINFO);
    ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
    ti.hwnd   = hWnd();
    ti.hinst  = hInstance();
105

106 107
    TCHAR HintText[100];
    RECT ActivateTTRect;
108

109 110 111 112 113 114 115
    //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);
116

117 118 119 120 121 122 123
    //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);
124

125 126 127 128 129 130 131
    //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);
132 133
}

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

141
            int HorizontalOffset = xControlsSpace;
142
            int ControlWidth = ButtonsWidth;
143 144 145 146 147 148 149
            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,
150
                        (WPARAM)IMAGE_BITMAP, (LPARAM)RC().hPlayBitmap);
151
            HorizontalOffset+=ControlWidth+xControlsSpace;
152 153

            ControlWidth = 200;
154 155 156 157 158 159 160
            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);
161 162 163 164 165
            HMODULE hThModule = LoadLibrary(TEXT("UxTheme.dll"));
            if(hThModule){
                FARPROC proc = GetProcAddress(hThModule, "SetWindowTheme");
                typedef HRESULT (WINAPI* SetWindowThemeProc)(HWND, LPCWSTR, LPCWSTR);
                if(proc){
166
                    ((SetWindowThemeProc)proc)(hVideoPosScroll, L"", L"");
167 168 169
                }
                FreeLibrary(hThModule);
            }
170
            HorizontalOffset+=ControlWidth+xControlsSpace;
171
            SendMessage(hVideoPosScroll, (UINT)PBM_SETRANGE, 0, MAKELPARAM(0, 1000));
172 173

            ControlWidth = ButtonsWidth;
174 175 176 177 178 179 180 181 182
            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;
183 184

            ControlWidth = 100;
185 186 187 188 189 190 191 192 193 194 195
            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;
196 197 198 199
            DWORD dwFSBtnStyle = WS_CHILD|BS_BITMAP|BS_FLAT;
            if( !PO() || PO()->get_enable_fs() ){
                dwFSBtnStyle |= WS_VISIBLE;
            }
200 201
            hFSButton =
                CreateWindow(TEXT("BUTTON"), TEXT("Toggle fullscreen"),
202
                             dwFSBtnStyle,
203 204 205 206
                             HorizontalOffset, xControlsSpace,
                             ControlWidth, ControlsHeight, hWnd(),
                             (HMENU)ID_FS_SWITCH_FS, 0, 0);
            SendMessage(hFSButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP,
207
                        (LPARAM)RC().hFullscreenBitmap);
208 209 210 211
            HorizontalOffset+=ControlWidth+xControlsSpace;

            RECT rect;
            GetClientRect(GetParent(hWnd()), &rect);
212 213

            int ControlWndWidth = HorizontalOffset;
214 215 216 217 218
            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);
219

220
            CreateToolTip();
221 222 223 224 225 226 227

            if( VP() ){
                RegisterToVLCEvents();
                UpdateVolumeSlider( VP()->get_mp().volume() );
                UpdateMuteButton( VP()->get_mp().mute() );
            }

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

311 312
            const int new_client_width = LOWORD(lParam);

313 314 315
            bool isFSBtnVisible =
                (GetWindowLong(hFSButton, GWL_STYLE) & WS_VISIBLE) != 0;

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
            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);

341 342 343 344 345 346 347
            RECT FSRect = {0, 0, 0, 0};
            if( isFSBtnVisible ) {
                GetWindowRect(hFSButton, &FSRect);
                VideoScrollWidth -= xControlsSpace;
                VideoScrollWidth -= (FSRect.right - FSRect.left);
                VideoScrollWidth -= xControlsSpace;
            }
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

            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;

377 378 379 380 381 382 383 384
            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);
            }
385 386 387 388

            EndDeferWindowPos(hDwp);
            break;
        }
389 390
        case WM_HSCROLL:
        case WM_VSCROLL: {
391 392
            if( hVolumeSlider == (HWND)lParam ){
                if( VP() ){
393
                    LRESULT SliderPos = SendMessage(hVolumeSlider, (UINT) TBM_GETPOS, 0, 0);
394
                    VP()->get_mp().setVolume( SliderPos );
395 396 397 398 399
                }
            }
            break;
        }
        default:
400
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
401 402
    }
    return 0L;
403 404
}

405
void VLCControlsWnd::RegisterToVLCEvents()
406
{
407
    VP()->get_mp().eventManager().onPositionChanged([this](float pos) {
408
        PostMessage(hVideoPosScroll, (UINT) PBM_SETPOS, (WPARAM)(pos * 1000), 0);
409
    });
410

411 412 413
    VP()->get_mp().eventManager().onPlaying([this] {
        PostMessage(hPlayPauseButton, BM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) RC().hPauseBitmap);
    });
414

415 416 417
    VP()->get_mp().eventManager().onPaused([this] {
        PostMessage(hPlayPauseButton, BM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) RC().hPlayBitmap);
    });
418 419 420

    VP()->get_mp().eventManager().onStopped([this] {
        PostMessage(hPlayPauseButton, BM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) RC().hPlayBitmap);
421 422 423 424 425 426
        PostMessage(hVideoPosScroll, (UINT) PBM_SETPOS, (WPARAM)0, 0);
    });

    VP()->get_mp().eventManager().onEndReached([this] {
        PostMessage(hPlayPauseButton, BM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) RC().hPlayBitmap);
        PostMessage(hVideoPosScroll, (UINT) PBM_SETPOS, (WPARAM)0, 0);
427
    });
428 429 430 431 432 433 434 435 436 437 438 439 440 441

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0)
    VP()->get_mp().eventManager().onAudioVolume([this](float vol) {
        UpdateVolumeSlider( roundf(vol * 100) );
    });

    VP()->get_mp().eventManager().onMuted([this] {
        UpdateMuteButton(true);
    });

    VP()->get_mp().eventManager().onUnmuted([this] {
        UpdateMuteButton(false);
    });
#endif
442 443 444 445
}

void VLCControlsWnd::NeedShowControls()
{
446 447 448 449
    if ( WM().IsFullScreen() || (PO() && PO()->get_show_toolbar()) )
    {
        SetWindowPos( hWnd(),  HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
        ShowWindow( hWnd(), SW_SHOW );
450
    }
451
    SetTimer(hWnd(), 1, 2 * 1000, nullptr);
452 453 454 455 456
}

void VLCControlsWnd::NeedHideControls()
{
    ShowWindow( hWnd(), SW_HIDE );
457
    KillTimer(hWnd(), 1);
458 459 460 461
}

void VLCControlsWnd::SetVideoPos(float Pos) //0-start, 1-end
{
462
    if( VP() ){
463 464 465
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
        VP()->get_mp().setPosition( Pos, true );
#else
466
        VP()->get_mp().setPosition( Pos );
467
#endif
468 469

        if( VP()->get_mp().length() > 0 )
470
            PostMessage(hVideoPosScroll, (UINT)PBM_SETPOS, (WPARAM) (Pos * 1000), 0);
471 472 473
    }
}

474
void VLCControlsWnd::UpdateVolumeSlider(unsigned int vol)
475
{
476 477 478
    const LRESULT SliderPos = SendMessage(hVolumeSlider, (UINT) TBM_GETPOS, 0, 0);
    if( (UINT)SliderPos != vol )
        PostMessage(hVolumeSlider, (UINT) TBM_SETPOS, (WPARAM) TRUE, (LPARAM) vol);
479 480
}

481
void VLCControlsWnd::UpdateMuteButton(bool muted)
482
{
483 484 485 486 487 488 489 490 491 492 493
    int MuteButtonState = SendMessage(hMuteButton, (UINT) BM_GETCHECK, 0, 0);
    if((muted&&(BST_UNCHECKED==MuteButtonState))||(!muted&&(BST_CHECKED==MuteButtonState))){
        PostMessage(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 ;
        PostMessage(hMuteButton, BM_SETIMAGE,
             (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
494 495 496
    }
}

497
void VLCControlsWnd::UpdateFullscreenButton(bool fullscreen)
498
{
499 500 501 502
    if (fullscreen)
        PostMessage( hFSButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM) RC().hDeFullscreenBitmap );
    else
        PostMessage( hFSButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM) RC().hFullscreenBitmap );
503 504
}

505 506 507
////////////////////////////////////////////////////////////////////////////////
//VLCHolderWnd members
////////////////////////////////////////////////////////////////////////////////
508

509 510 511
VLCHolderWnd*
VLCHolderWnd::CreateHolderWindow(HINSTANCE hInstance,
                                 HWND hParentWnd, VLCWindowsManager* WM)
512
{
513 514 515
    VLCHolderWnd* wnd = new VLCHolderWnd(hInstance, WM);
    if( wnd && wnd->Create(hParentWnd) ) {
        return wnd;
516
    }
517 518
    delete wnd;
    return 0;
519 520
}

521
VLCHolderWnd::~VLCHolderWnd()
522
{
523 524 525 526
    if(_hBgBrush) {
        DeleteObject(_hBgBrush);
        _hBgBrush = 0;
    }
527 528
}

529
bool VLCHolderWnd::Create(HWND hWndParent)
530
{
531 532 533
    return VLCWnd::Create(TEXT("Holder Window"),
                            WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_VISIBLE,
                            0, 0, 0, 0, hWndParent, 0);
534 535
}

536
void VLCHolderWnd::PreRegisterWindowClass(WNDCLASS* wc)
537
{
538
    if( !_hBgBrush){
539
        unsigned r = 0, g = 0, b = 0;
540
        HTMLColor2RGB(PO()->get_bg_color().c_str(), &r, &g, &b);
541 542 543 544
        _hBgBrush = CreateSolidBrush(RGB(r, g, b));
    }

    wc->hbrBackground = _hBgBrush;
545 546
    wc->lpszClassName = TEXT("Web Plugin VLC Window Holder Class");
}
547

548 549
LRESULT VLCHolderWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
550 551 552 553 554 555 556
    switch( uMsg )
    {
        case WM_CREATE:{
            CREATESTRUCT* CreateStruct = (CREATESTRUCT*)(lParam);

            RECT ParentClientRect;
            GetClientRect(CreateStruct->hwndParent, &ParentClientRect);
557
            MoveWindow(hWnd(), 0, 0,
558 559
                       (ParentClientRect.right-ParentClientRect.left),
                       (ParentClientRect.bottom-ParentClientRect.top), FALSE);
560 561 562
            _CtrlsWnd =
                VLCControlsWnd::CreateControlsWindow(hInstance(), _wm,
                                                     hWnd());
563 564 565 566 567 568 569 570 571 572 573
            // This needs to access the media player HWND, therefore we need
            // to wait for the vout to be created
            VP()->get_mp().eventManager().onVout([this](int nbVout) {
                if ( nbVout == 0 )
                    return;
                HWND hwnd = FindMP_hWnd();
                if ( hwnd == nullptr )
                    return;
                DWORD s = GetWindowLong(hwnd, GWL_STYLE);
                s |= WS_CLIPSIBLINGS;
                SetWindowLong(hwnd, GWL_STYLE, s);
574 575 576 577

                //libvlc events arrives from separate thread,
                //so we need post message to main thread, to notify it.
                PostMessage(hWnd(), WM_SET_MOUSE_HOOK, 0, 0);
578
            });
579 580
            break;
        }
581 582
        case WM_SET_MOUSE_HOOK:{
            MouseHook(true);
583
            KeyboardHook(true);
584 585
            break;
        }
586 587
        case WM_PAINT:{
            PAINTSTRUCT PaintStruct;
588
            HDC hDC = BeginPaint(hWnd(), &PaintStruct);
589 590 591 592 593 594 595 596
            if( PO() && PO()->get_enable_branding() )
            {
                RECT rect;
                GetClientRect(hWnd(), &rect);
                int IconX = ((rect.right - rect.left) - GetSystemMetrics(SM_CXICON))/2;
                int IconY = ((rect.bottom - rect.top) - GetSystemMetrics(SM_CYICON))/2;
                DrawIcon(hDC, IconX, IconY, RC().hBackgroundIcon);
            }
597
            EndPaint(hWnd(), &PaintStruct);
598 599
            break;
        }
600 601
        case WM_SHOWWINDOW:{
            if(FALSE!=wParam){ //showing
602
                _CtrlsWnd->NeedShowControls();
603 604 605 606
            }
            break;
        }
        case WM_SIZE:
607
            if(_CtrlsWnd){
608 609 610 611
                int new_client_width = LOWORD(lParam);
                int new_client_height = HIWORD(lParam);

                RECT rect;
612
                GetWindowRect(_CtrlsWnd->hWnd(), &rect);
613

614
                MoveWindow(_CtrlsWnd->hWnd(),
615 616 617 618
                           0, new_client_height - (rect.bottom - rect.top),
                           new_client_width, (rect.bottom-rect.top), TRUE);
            }
            break;
619
        case WM_MOUSEMOVE:
620
            WM().OnMouseEvent(uMsg, wParam, lParam);
621 622 623 624 625 626 627
            if (_CtrlsWnd && (_oldMouseCoords.x != GET_X_LPARAM(lParam) ||
                _oldMouseCoords.y != GET_Y_LPARAM(lParam)))
            {
                _CtrlsWnd->NeedShowControls();
                _oldMouseCoords = MAKEPOINTS(lParam);
            }
            break;
628 629

        case WM_MBUTTONDBLCLK:
630
        case WM_LBUTTONDBLCLK:
631 632 633 634 635 636 637 638 639 640 641 642
        case WM_RBUTTONDBLCLK:
        case WM_XBUTTONDBLCLK:
        case WM_MBUTTONUP:
        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
        case WM_XBUTTONUP:
        case WM_MBUTTONDOWN:
        case WM_LBUTTONDOWN:
        case WM_RBUTTONDOWN:
        case WM_XBUTTONDOWN:
            WM().OnMouseEvent(uMsg, wParam, lParam);
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
643
            break;
644 645 646 647 648 649

        case WM_CHAR:
        case WM_KEYUP:
        case WM_KEYDOWN:
            WM().OnKeyEvent(uMsg, wParam, lParam);
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
650
        case WM_MOUSE_EVENT_NOTIFY:{
651 652 653 654
            // This is called synchronously, though handling it directly from the mouse hook
            // deadlocks (quite likely because we're destroying the windows we're being called from)
            // Just repost this asynchronously, and let the called know we received the message.
            PostMessage(hWnd(), WM_MOUSE_EVENT_REPOST, wParam, lParam);
655 656
            return WM_MOUSE_EVENT_NOTIFY_SUCCESS;
        }
657
        case WM_MOUSE_EVENT_REPOST:
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
        {
            //on click set focus to the parent of MP to receice key events
            switch (wParam) {
                case WM_RBUTTONUP:
                case WM_MBUTTONUP:
                case WM_LBUTTONUP:
                case WM_XBUTTONUP:
                {
                    HWND mphwnd = FindMP_hWnd();
                    if (mphwnd)
                        SetFocus(GetParent(mphwnd));
                   break;
                }
            }
            WM().OnMouseEvent(uMsg, wParam, lParam);
            break;
        }
        case WM_KEYBOARD_EVENT_NOTIFY:{
            PostMessage(hWnd(), WM_KEYBOARD_EVENT_REPOST, wParam, lParam);
            return WM_KEYBOARD_EVENT_NOTIFY_SUCCESS;
        }
        case WM_KEYBOARD_EVENT_REPOST:
            if ((lParam & 0xA0000000) == 0)
                WM().OnKeyEvent(WM_KEYDOWN, wParam, lParam);
            else
                WM().OnKeyEvent(WM_KEYUP, wParam, lParam);
684
            break;
685
        default:
686
            return VLCWnd::WindowProc(uMsg, wParam, lParam);
687 688
    }
    return 0;
689
}
690 691 692

void VLCHolderWnd::DestroyWindow()
{
693 694 695 696 697
    if(_CtrlsWnd){
        delete _CtrlsWnd;
        _CtrlsWnd = 0;
    }

698 699
    if(hWnd())
        ::DestroyWindow(hWnd());
700
}
701 702

LRESULT CALLBACK VLCHolderWnd::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
703
{
704 705 706
    if(nCode >= 0){
        switch(wParam){
            case WM_MOUSEMOVE:
707 708 709 710 711 712 713 714 715 716 717 718 719
            case WM_RBUTTONDBLCLK:
            case WM_MBUTTONDBLCLK:
            case WM_LBUTTONDBLCLK:
            case WM_XBUTTONDBLCLK:
            case WM_RBUTTONDOWN:
            case WM_MBUTTONDOWN:
            case WM_LBUTTONDOWN:
            case WM_XBUTTONDOWN:
            case WM_RBUTTONUP:
            case WM_MBUTTONUP:
            case WM_LBUTTONUP:
            case WM_XBUTTONUP:
            {
720
                MOUSEHOOKSTRUCT* mhs = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
721

722 723 724 725 726 727 728 729
                //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);
                }
                break;
730 731 732 733
            }
        }
    }

734
    return CallNextHookEx(NULL, nCode, wParam, lParam);
735 736
}

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754

LRESULT CALLBACK VLCHolderWnd::KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode != HC_ACTION)
        return CallNextHookEx(NULL, nCode, wParam, lParam);

    //try to find HolderWnd and notify it
    HWND hNotifyWnd = ::GetFocus();
    LRESULT SMRes = ::SendMessage(hNotifyWnd, WM_KEYBOARD_EVENT_NOTIFY, wParam, lParam);
    while( hNotifyWnd && WM_KEYBOARD_EVENT_NOTIFY_SUCCESS != SMRes){
        hNotifyWnd = GetParent(hNotifyWnd);
        SMRes = ::SendMessage(hNotifyWnd, WM_KEYBOARD_EVENT_NOTIFY, wParam, lParam);
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}


755
void VLCHolderWnd::MouseHook(bool SetHook)
756
{
757
    if(SetHook){
758 759 760
        HWND hMPWnd = FindMP_hWnd();
        const DWORD WndThreadID = (hMPWnd) ? GetWindowThreadProcessId(hMPWnd, NULL) : 0;
        if( _hMouseHook &&( !hMPWnd || WndThreadID != _MouseHookThreadId) ){
761 762 763
            //unhook if something changed
            MouseHook(false);
        }
764

765
        if(!_hMouseHook && hMPWnd && WndThreadID){
766 767 768 769 770 771 772 773 774 775 776 777
            _MouseHookThreadId = WndThreadID;
            _hMouseHook =
                SetWindowsHookEx(WH_MOUSE, VLCHolderWnd::MouseHookProc,
                                 NULL, WndThreadID);
        }
    }
    else{
        if(_hMouseHook){
            UnhookWindowsHookEx(_hMouseHook);
            _MouseHookThreadId=0;
            _hMouseHook = 0;
        }
778 779 780
    }
}

781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
void VLCHolderWnd::KeyboardHook(bool SetHook)
{
    if(SetHook){
        HWND hMPWnd = FindMP_hWnd();
        const DWORD WndThreadID = (hMPWnd) ? GetWindowThreadProcessId(hMPWnd, NULL) : 0;
        if( _hKeyboardHook &&( !hMPWnd || WndThreadID != _KeyboardHookThreadId) ){
            //unhook if something changed
            KeyboardHook(false);
        }

        if(!_hKeyboardHook && hMPWnd && WndThreadID){
            _KeyboardHookThreadId = WndThreadID;
            _hKeyboardHook =
                SetWindowsHookEx(WH_KEYBOARD, VLCHolderWnd::KeyboardHookProc,
                                 NULL, WndThreadID);
        }
    }
    else{
        if(_hKeyboardHook){
            UnhookWindowsHookEx(_hKeyboardHook);
            _KeyboardHookThreadId=0;
            _hKeyboardHook = 0;
        }
    }
}


808 809 810 811 812
HWND VLCHolderWnd::FindMP_hWnd()
{
    if(_CtrlsWnd)
        return GetWindow(_CtrlsWnd->hWnd(), GW_HWNDNEXT);
    else
813
        return GetWindow(hWnd(), GW_CHILD);
814 815
}

816 817 818 819 820
////////////////////////////////////////////////////////////////////////////////
//VLCFullScreenWnd members
////////////////////////////////////////////////////////////////////////////////
HINSTANCE VLCFullScreenWnd::_hinstance = 0;
ATOM VLCFullScreenWnd::_fullscreen_wndclass_atom = 0;
821

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

827
    WNDCLASS wClass;
828

829 830 831 832 833 834 835 836 837 838 839 840 841
    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();
842

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

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

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

    switch( uMsg )
864
    {
865 866 867 868 869 870 871
        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));

872
            break;
873 874 875 876
        }
        case WM_NCDESTROY:
            delete fs_data;
            SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
877
            break;
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
        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();
893 894 895
                SetWindowPos(HolderWnd->hWnd(), HWND_BOTTOM, 0, 0,
                             new_client_width, new_client_height,
                             SWP_NOACTIVATE|SWP_NOOWNERZORDER);
896
            }
897
            break;
898
        }
899 900 901 902

        case WM_CHAR:
        case WM_SYSKEYUP:
        case WM_KEYUP:
903
            if (fs_data)
904 905 906 907 908 909 910 911 912
                fs_data->_WindowsManager->OnKeyEvent(uMsg, wParam, lParam);
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        case WM_SYSKEYDOWN:
        case WM_KEYDOWN: {
            if (fs_data) {
                fs_data->_WindowsManager->OnKeyEvent(uMsg, wParam, lParam);
                fs_data->_WindowsManager->OnKeyDownEvent(uMsg, wParam, lParam);
            }
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
913
        }
914 915
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
916
    }
917 918
    return 0L;
};
919

920
VLCFullScreenWnd* VLCFullScreenWnd::CreateFSWindow(VLCWindowsManager* WM)
921
{
922
    HWND hWnd = CreateWindow(getClassName(),
923
                TEXT("VLC Full Screen Window"),
924 925 926 927 928 929 930 931 932
                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));
933

934
    return 0;
935 936 937 938 939
}

///////////////////////
//VLCWindowsManager
///////////////////////
940
VLCWindowsManager::VLCWindowsManager(HMODULE hModule, const VLCViewResources& rc,
941 942
                                     vlc_player* player, const vlc_player_options* po,
                                     InputObserver* observer)
943
    :_rc(rc), _hModule(hModule), _po(po), _hWindowedParentWnd(0), _vp(player),
944
    _HolderWnd(0), _FSWnd(0), _InputObserver(observer), _b_new_messages_flag(false), Last_WM_MOUSEMOVE_Pos(0)
945 946 947 948 949 950 951 952 953 954 955 956 957 958
{
    VLCFullScreenWnd::RegisterWndClassName(hModule);
}

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

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

    if(!_HolderWnd){
959 960 961
        _HolderWnd =
            VLCHolderWnd::CreateHolderWindow(getHModule(),
                                             hWindowedParentWnd, this);
962 963 964 965 966
    }
}

void VLCWindowsManager::DestroyWindows()
{
967 968
    if(_HolderWnd){
        _HolderWnd->DestroyWindow();
969 970
        delete _HolderWnd;
        _HolderWnd = 0;
971
    }
972 973 974 975 976

    if(_FSWnd){
        _FSWnd->DestroyWindow();
    }
    _FSWnd = 0;
977 978 979 980
}

void VLCWindowsManager::StartFullScreen()
{
981
    if( !_HolderWnd || ( PO() && !PO()->get_enable_fs() ) )
982 983
        return;//VLCWindowsManager::CreateWindows was not called

984 985
    if( VP() && !IsFullScreen() ){
        if( !_FSWnd ){
986 987 988
            _FSWnd= VLCFullScreenWnd::CreateFSWindow(this);
        }

989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
        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

1006
        SetParent(_HolderWnd->hWnd(), _FSWnd->getHWND());
1007 1008 1009 1010
        SetWindowPos(_FSWnd->getHWND(), HWND_TOPMOST,
                     FSRect.left, FSRect.top,
                     FSRect.right - FSRect.left, FSRect.bottom - FSRect.top,
                     FSFlags);
1011 1012

        ShowWindow(_FSWnd->getHWND(), SW_SHOW);
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025

        HWND controlWindow = _HolderWnd->ControlWindow()->hWnd();
        //parenting to NULL promotes window to WS_POPUP
        SetParent(controlWindow, NULL);
        //Ensure control window is on the right screen
        RECT controlRect;
        GetWindowRect(controlWindow, &controlRect);
        OffsetRect(&controlRect, FSRect.left - controlRect.left, FSRect.bottom - controlRect.bottom);
        SetWindowPos(controlWindow,  HWND_TOPMOST,
                     controlRect.left, controlRect.top,
                     controlRect.right - controlRect.left, controlRect.bottom - controlRect.top,
                     SWP_FRAMECHANGED);

1026 1027 1028 1029 1030
    }
}

void VLCWindowsManager::EndFullScreen()
{
1031 1032 1033
    if(!_HolderWnd)
        return;//VLCWindowsManager::CreateWindows was not called

1034
    if(IsFullScreen()){
1035
        SetParent(_HolderWnd->hWnd(), _hWindowedParentWnd);
1036 1037 1038

        RECT WindowedParentRect;
        GetClientRect(_hWindowedParentWnd, &WindowedParentRect);
1039 1040
        MoveWindow(_HolderWnd->hWnd(), 0, 0,
                   WindowedParentRect.right, WindowedParentRect.bottom, FALSE);
1041 1042

        ShowWindow(_FSWnd->getHWND(), SW_HIDE);
1043

1044 1045
        _FSWnd->DestroyWindow();
        _FSWnd = nullptr;
1046 1047 1048 1049

        HWND controlWindow = _HolderWnd->ControlWindow()->hWnd();
        SetParent(controlWindow, _HolderWnd->hWnd());
        SetWindowPos(controlWindow,  HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
1050
   }
1051 1052 1053 1054
}

void VLCWindowsManager::ToggleFullScreen()
{
1055 1056
    auto isFullscreen = IsFullScreen();
    if ( isFullscreen ){
1057 1058 1059 1060 1061
        EndFullScreen();
    }
    else{
        StartFullScreen();
    }
1062
    _HolderWnd->ControlWindow()->UpdateFullscreenButton( !isFullscreen );
1063 1064 1065 1066
}

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

1070
void VLCWindowsManager::OnKeyDownEvent(UINT uKeyMsg, WPARAM wParam, LPARAM lParam)
1071
{
1072
    switch(wParam){
1073 1074 1075
        case VK_ESCAPE:
        case 'F':
            EndFullScreen();
1076
            _HolderWnd->ControlWindow()->UpdateFullscreenButton( FALSE );
1077 1078 1079 1080
            break;
    }
}

1081
void VLCWindowsManager::OnKeyEvent(UINT uKeyMsg, WPARAM wParam, LPARAM lParam)
1082
{
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
    if (_InputObserver)
        this->_InputObserver->OnKeyEvent(uKeyMsg, wParam, lParam);
}

void VLCWindowsManager::OnMouseEvent(UINT uMouseMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMouseMsg == WM_MOUSE_EVENT_REPOST)
    {
        DWORD MsgPos = GetMessagePos();
        switch(wParam){
            case WM_LBUTTONDBLCLK:
                ToggleFullScreen();
                break;
            case WM_MOUSEMOVE:{
                DWORD MsgPos = GetMessagePos();
                if(Last_WM_MOUSEMOVE_Pos != MsgPos){
                    Last_WM_MOUSEMOVE_Pos = MsgPos;
                    _HolderWnd->ControlWindow()->NeedShowControls();
                }
                break;
1103 1104
            }
        }
1105 1106
        if (_InputObserver)
            this->_InputObserver->OnMouseEvent(wParam, lParam, MsgPos);
1107
    }
1108 1109
    else if (_InputObserver)
        this->_InputObserver->OnMouseEvent(uMouseMsg, wParam, lParam);
1110
}
1111