Belloc
Belloc

Reputation: 6390

Why does it take so long to hear the beep when dragging the app window side a little bit faster?

This is a very simple code using the Windows API, where a child window is painted in the central part of the app window. By clicking with the mouse left button on the main window client area, the child window assumes a null height. By clicking with the mouse right button, the child window has its height increased by 10 pixels, at each mouse click. One can hear a beep every time a left, or right mouse click occurs in the window's app, due to the MessageBeep(-1) call made while painting the parent window.

The curious thing is that when you drag one of the sides of the parent window, changing its width or height, very slowly, you can hear the beeps, at each move. But if you drag the window's side a little bit faster, you'll hear just one beep, many many seconds after the mouse button was released. Why is that?

This is the code:

#include <windows.h>

LRESULT CALLBACK        WindowProc(HWND, UINT, UINT, LONG);
LRESULT CALLBACK        ChildProc(HWND, UINT, UINT, LONG);

/****************************************************************************************************************************

    WinMain()

****************************************************************************************************************************/

int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
    MSG         msg;
    WNDCLASSEX  wndclassx;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = 0;
    wndclassx.lpfnWndProc   = WindowProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = 0;
    wndclassx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszMenuName  = NULL;
    wndclassx.lpszClassName = L"ParentWindow";
    wndclassx.hIconSm       = NULL;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = 0;
    wndclassx.lpfnWndProc   = ChildProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = 0;
    wndclassx.hCursor       = 0;
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszMenuName  = NULL;
    wndclassx.lpszClassName = L"ChildWindow";
    wndclassx.hIconSm       = NULL;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    HWND hWnd;

    if( !(hWnd = CreateWindow(L"ParentWindow", L"Parent Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL)) ) return 0;

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    while( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

/****************************************************************************************************************************

    WindowProc()

****************************************************************************************************************************/

LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    PAINTSTRUCT ps;

    switch ( message )
    {
        RECT rect;
        HWND    hChild;

        case WM_CREATE:

        GetClientRect(hwnd, &rect);

        if( !CreateWindow(L"ChildWindow", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, rect.right / 3, rect.bottom / 3, rect.right / 3,
                          rect.bottom / 3, hwnd, (HMENU)0, ((LPCREATESTRUCT)lParam)->hInstance, NULL) ) return -1;
        break;

        case WM_SIZE:

        MoveWindow(GetDlgItem(hwnd, 0), LOWORD(lParam) / 3, HIWORD(lParam) / 3, LOWORD(lParam) / 3, HIWORD(lParam) / 3,
                   true);

        break;

        case WM_LBUTTONDOWN:

        hChild = GetDlgItem(hwnd, 0);

        GetWindowRect(hChild, &rect);


        ScreenToClient(hwnd, (LPPOINT)&rect);


        ScreenToClient(hwnd, (LPPOINT)&rect.right);

        MoveWindow(hChild, rect.left, rect.top, rect.right - rect.left, 0, true);
        break;

        case WM_RBUTTONDOWN:

        hChild = GetDlgItem(hwnd, 0);

        GetWindowRect(hChild, &rect);

        ScreenToClient(hwnd, (LPPOINT)&rect);

        ScreenToClient(hwnd, (LPPOINT)&rect.right);

        MoveWindow(hChild, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + 10, true);
        break;

        case WM_PAINT:
        BeginPaint(hwnd, &ps);
        MessageBeep(-1);
        EndPaint(hwnd, &ps);
        break;

        case WM_DESTROY:

        PostQuitMessage(0);
        break;

        default:

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

/****************************************************************************************************************************

    ChildProc()

****************************************************************************************************************************/

LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    switch( message )
    {
        default:

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

Upvotes: 0

Views: 80

Answers (1)

MSN
MSN

Reputation: 54584

To quote from this KB article on MSDN:

With normal use of GetMessage() (passing zeros for all arguments except the LPMSG parameter) or PeekMessage(), any message on the application queue is processed before user input messages. And input messages are processed before WM_TIMER and WM_PAINT "messages."

In other words, because you call MessageBeep during WM_PAINT, it won't happen until after the window stops processing user input, e.g., when the user stops moving the window around.

Upvotes: 1

Related Questions