root/modules/highgui/src/window_w32.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FillBitmapInfo
  2. icvCleanupHighgui
  3. cvInitSystem
  4. cvStartWindowThread
  5. icvFindWindowByName
  6. icvWindowByHWND
  7. icvTrackbarByHWND
  8. icvLoadWindowPos
  9. icvSaveWindowPos
  10. cvGetModeWindow_W32
  11. cvSetModeWindow_W32
  12. setWindowTitle
  13. cvGetPropWindowAutoSize_W32
  14. cvGetRatioWindow_W32
  15. cvGetOpenGlProp_W32
  16. createGlContext
  17. releaseGlContext
  18. drawGl
  19. resizeGl
  20. cvNamedWindow
  21. cvSetOpenGlContext
  22. cvUpdateWindow
  23. cvSetOpenGlDrawCallback
  24. icvRemoveWindow
  25. cvDestroyWindow
  26. icvScreenToClient
  27. icvCalcWindowRect
  28. icvGetBitmapData
  29. icvUpdateWindowPos
  30. cvShowImage
  31. cvShowImageHWND
  32. cvResizeWindow
  33. cvMoveWindow
  34. MainWindowProc
  35. HighGUIProc
  36. WindowProc
  37. icvUpdateTrackbar
  38. HGToolbarProc
  39. cvDestroyAllWindows
  40. showSaveDialog
  41. cvWaitKey
  42. icvFindTrackbarByName
  43. icvCreateTrackbar
  44. cvCreateTrackbar
  45. cvCreateTrackbar2
  46. cvSetMouseCallback
  47. cvGetTrackbarPos
  48. cvSetTrackbarPos
  49. cvSetTrackbarMax
  50. cvGetWindowHandle
  51. cvGetWindowName
  52. cvSetPreprocessFuncWin32_
  53. cvSetPostprocessFuncWin32_

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"
#include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros

#if defined WIN32 || defined _WIN32

#ifdef __GNUC__
#  pragma GCC diagnostic ignored "-Wmissing-declarations"
#endif

#if (_WIN32_IE < 0x0500)
#pragma message("WARNING: Win32 UI needs to be compiled with _WIN32_IE >= 0x0500 (_WIN32_IE_IE50)")
#define _WIN32_IE 0x0500
#endif

#include <commctrl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>

#ifdef HAVE_OPENGL
#include <memory>
#include <algorithm>
#include <vector>
#include <functional>
#include "opencv2/highgui.hpp"
#include <GL\gl.h>
#endif

static const char* trackbar_text =
"                                                                                             ";

#if defined _M_X64 || defined __x86_64

#define icvGetWindowLongPtr GetWindowLongPtr
#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
#define icvGetClassLongPtr  GetClassLongPtr

#define CV_USERDATA GWLP_USERDATA
#define CV_WNDPROC GWLP_WNDPROC
#define CV_HCURSOR GCLP_HCURSOR
#define CV_HBRBACKGROUND GCLP_HBRBACKGROUND

#else

#define icvGetWindowLongPtr GetWindowLong
#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
#define icvGetClassLongPtr GetClassLong

#define CV_USERDATA GWL_USERDATA
#define CV_WNDPROC GWL_WNDPROC
#define CV_HCURSOR GCL_HCURSOR
#define CV_HBRBACKGROUND GCL_HBRBACKGROUND

#endif

#ifndef WM_MOUSEHWHEEL
    #define WM_MOUSEHWHEEL 0x020E
#endif

static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
{
    assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));

    BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

    memset( bmih, 0, sizeof(*bmih));
    bmih->biSize = sizeof(BITMAPINFOHEADER);
    bmih->biWidth = width;
    bmih->biHeight = origin ? abs(height) : -abs(height);
    bmih->biPlanes = 1;
    bmih->biBitCount = (unsigned short)bpp;
    bmih->biCompression = BI_RGB;

    if( bpp == 8 )
    {
        RGBQUAD* palette = bmi->bmiColors;
        int i;
        for( i = 0; i < 256; i++ )
        {
            palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
            palette[i].rgbReserved = 0;
        }
    }
}

struct CvWindow;

typedef struct CvTrackbar
{
    int signature;
    HWND hwnd;
    char* name;
    CvTrackbar* next;
    CvWindow* parent;
    HWND buddy;
    int* data;
    int pos;
    int maxval;
    void (*notify)(int);
    void (*notify2)(int, void*);
    void* userdata;
    int id;
}
CvTrackbar;


typedef struct CvWindow
{
    int signature;
    HWND hwnd;
    char* name;
    CvWindow* prev;
    CvWindow* next;
    HWND frame;

    HDC dc;
    HGDIOBJ image;
    int last_key;
    int flags;
    int status;//0 normal, 1 fullscreen (YV)

    CvMouseCallback on_mouse;
    void* on_mouse_param;

    struct
    {
        HWND toolbar;
        int pos;
        int rows;
        WNDPROC toolBarProc;
        CvTrackbar* first;
    }
    toolbar;

    int width;
    int height;

    // OpenGL support

#ifdef HAVE_OPENGL
    bool useGl;
    HGLRC hGLRC;

    CvOpenGlDrawCallback glDrawCallback;
    void* glDrawData;
#endif
}
CvWindow;

#define HG_BUDDY_WIDTH  130

#ifndef TBIF_SIZE
    #define TBIF_SIZE  0x40
#endif

#ifndef TB_SETBUTTONINFO
    #define TB_SETBUTTONINFO (WM_USER + 66)
#endif

#ifndef TBM_GETTOOLTIPS
    #define TBM_GETTOOLTIPS  (WM_USER + 30)
#endif

static LRESULT CALLBACK HighGUIProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK MainWindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void icvUpdateWindowPos( CvWindow* window );

static CvWindow* hg_windows = 0;

typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
static HINSTANCE hg_hinstance = 0;

static const char* highGUIclassName = "HighGUI class";
static const char* mainHighGUIclassName = "Main HighGUI class";

static void icvCleanupHighgui()
{
    cvDestroyAllWindows();
    UnregisterClass(highGUIclassName, hg_hinstance);
    UnregisterClass(mainHighGUIclassName, hg_hinstance);
}

CV_IMPL int cvInitSystem( int, char** )
{
    static int wasInitialized = 0;

    // check initialization status
    if( !wasInitialized )
    {
        // Initialize the stogare
        hg_windows = 0;

        // Register the class
        WNDCLASS wndc;
        wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
        wndc.lpfnWndProc = WindowProc;
        wndc.cbClsExtra = 0;
        wndc.cbWndExtra = 0;
        wndc.hInstance = hg_hinstance;
        wndc.lpszClassName = highGUIclassName;
        wndc.lpszMenuName = highGUIclassName;
        wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
        wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
        wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);

        RegisterClass(&wndc);

        wndc.lpszClassName = mainHighGUIclassName;
        wndc.lpszMenuName = mainHighGUIclassName;
        wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
        wndc.lpfnWndProc = MainWindowProc;

        RegisterClass(&wndc);
        atexit( icvCleanupHighgui );

        wasInitialized = 1;
    }

    setlocale(LC_NUMERIC,"C");

    return 0;
}

CV_IMPL int cvStartWindowThread(){
    return 0;
}

static CvWindow* icvFindWindowByName( const char* name )
{
    CvWindow* window = hg_windows;

    for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
        ;

    return window;
}


static CvWindow* icvWindowByHWND( HWND hwnd )
{
    CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
    return window != 0 && hg_windows != 0 &&
           window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
}


static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
{
    CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
    return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
           trackbar->hwnd == hwnd ? trackbar : 0;
}


static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";

// Window positions saving/loading added by Philip Gruebele.
//<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
// Restores the window position from the registry saved position.
static void
icvLoadWindowPos( const char* name, CvRect& rect )
{
    HKEY hkey;
    char szKey[1024];
    strcpy( szKey, icvWindowPosRootKey );
    strcat( szKey, name );

    rect.x = rect.y = CW_USEDEFAULT;
    rect.width = rect.height = 320;

    if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
    {
        // Yes we are installed.
        DWORD dwType = 0;
        DWORD dwSize = sizeof(int);

        RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
        RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
        RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
        RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);

        if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) )
            rect.x = 100;
        if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) )
            rect.y = 100;

        if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) )
            rect.width = 100;
        if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) )
            rect.height = 100;

        RegCloseKey(hkey);
    }
}


// Window positions saving/loading added by Philip Gruebele.
//<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
// philipg.  Saves the window position in the registry
static void
icvSaveWindowPos( const char* name, CvRect rect )
{
    static const DWORD MAX_RECORD_COUNT = 100;
    HKEY hkey;
    char szKey[1024];
    char rootKey[1024];
    strcpy( szKey, icvWindowPosRootKey );
    strcat( szKey, name );

    if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
    {
        HKEY hroot;
        DWORD count = 0;
        FILETIME oldestTime = { UINT_MAX, UINT_MAX };
        char oldestKey[1024];
        char currentKey[1024];

        strcpy( rootKey, icvWindowPosRootKey );
        rootKey[strlen(rootKey)-1] = '\0';
        if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
            //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
            return;

        for(;;)
        {
            DWORD csize = sizeof(currentKey);
            FILETIME accesstime = { 0, 0 };
            LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
            if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
                break;
            count++;
            if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
                (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
                oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
            {
                oldestTime = accesstime;
                strcpy( oldestKey, currentKey );
            }
        }

        if( count >= MAX_RECORD_COUNT )
            RegDeleteKey( hroot, oldestKey );
        RegCloseKey( hroot );

        if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
            return;
    }
    else
    {
        RegCloseKey( hkey );
        if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
            return;
    }

    RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
    RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
    RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
    RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
    RegCloseKey(hkey);
}

double cvGetModeWindow_W32(const char* name)//YV
{
    double result = -1;

    CV_FUNCNAME( "cvGetModeWindow_W32" );

    __BEGIN__;

    CvWindow* window;

    if (!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        EXIT; // keep silence here

    result = window->status;

    __END__;
    return result;
}

void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
{
    CV_FUNCNAME( "cvSetModeWindow_W32" );

    __BEGIN__;

    CvWindow* window;

    if(!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if( !window )
        CV_ERROR( CV_StsNullPtr, "NULL window" );

    if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
        EXIT;

    {
        DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
        CvRect position;

        if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
        {
            icvLoadWindowPos(window->name,position );
            SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);

            SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
            window->status=CV_WINDOW_NORMAL;

            EXIT;
        }

        if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
        {
            //save dimension
            RECT rect;
            GetWindowRect(window->frame, &rect);
            CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
            icvSaveWindowPos(window->name,RectCV );

            //Look at coordinate for fullscreen
            HMONITOR hMonitor;
            MONITORINFO mi;
            hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);

            mi.cbSize = sizeof(mi);
            GetMonitorInfo(hMonitor, &mi);

            //fullscreen
            position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top;
            position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top;
            SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);

            SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
            window->status=CV_WINDOW_FULLSCREEN;

            EXIT;
        }
    }

    __END__;
}

void cv::setWindowTitle(const String& winname, const String& title)
{
    CvWindow* window = icvFindWindowByName(winname.c_str());

    if (!window)
    {
        namedWindow(winname);
        window = icvFindWindowByName(winname.c_str());
    }

    if (!window)
        CV_Error(Error::StsNullPtr, "NULL window");

    if (!SetWindowText(window->frame, title.c_str()))
        CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", winname.c_str(), title.c_str()));
}

double cvGetPropWindowAutoSize_W32(const char* name)
{
    double result = -1;

    CV_FUNCNAME( "cvSetCloseCallback" );

    __BEGIN__;

    CvWindow* window;

    if (!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        EXIT; // keep silence here

    result = window->flags & CV_WINDOW_AUTOSIZE;

    __END__;

    return result;
}

double cvGetRatioWindow_W32(const char* name)
{
    double result = -1;

    CV_FUNCNAME( "cvGetRatioWindow_W32" );

    __BEGIN__;

    CvWindow* window;

    if (!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        EXIT; // keep silence here

    result = static_cast<double>(window->width) / window->height;

    __END__;

    return result;
}

double cvGetOpenGlProp_W32(const char* name)
{
    double result = -1;

#ifdef HAVE_OPENGL
    CV_FUNCNAME( "cvGetOpenGlProp_W32" );

    __BEGIN__;

    CvWindow* window;

    if (!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        EXIT; // keep silence here

    result = window->useGl;

    __END__;
#endif
    (void)name;

    return result;
}


// OpenGL support

#ifdef HAVE_OPENGL

namespace
{
    void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
    {
        CV_FUNCNAME( "createGlContext" );

        __BEGIN__;

        useGl = false;

        int PixelFormat;

        static PIXELFORMATDESCRIPTOR pfd =
        {
            sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
            1,                             // Version Number
            PFD_DRAW_TO_WINDOW |           // Format Must Support Window
            PFD_SUPPORT_OPENGL |           // Format Must Support OpenGL
            PFD_DOUBLEBUFFER,              // Must Support Double Buffering
            PFD_TYPE_RGBA,                 // Request An RGBA Format
            32,                            // Select Our Color Depth
            0, 0, 0, 0, 0, 0,              // Color Bits Ignored
            0,                             // No Alpha Buffer
            0,                             // Shift Bit Ignored
            0,                             // No Accumulation Buffer
            0, 0, 0, 0,                    // Accumulation Bits Ignored
            32,                            // 32 Bit Z-Buffer (Depth Buffer)
            0,                             // No Stencil Buffer
            0,                             // No Auxiliary Buffer
            PFD_MAIN_PLANE,                // Main Drawing Layer
            0,                             // Reserved
            0, 0, 0                        // Layer Masks Ignored
        };

        hGLDC = GetDC(hWnd);
        if (!hGLDC)
            CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );

        PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
        if (!PixelFormat)
            CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );

        if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
            CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );

        hGLRC = wglCreateContext(hGLDC);
        if (!hGLRC)
            CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );

        if (!wglMakeCurrent(hGLDC, hGLRC))
            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );

        useGl = true;

        __END__;
    }

    void releaseGlContext(CvWindow* window)
    {
        //CV_FUNCNAME( "releaseGlContext" );

        __BEGIN__;

        if (window->hGLRC)
        {
            wglDeleteContext(window->hGLRC);
            window->hGLRC = NULL;
        }

        if (window->dc)
        {
            ReleaseDC(window->hwnd, window->dc);
            window->dc = NULL;
        }

        window->useGl = false;

        __END__;
    }

    void drawGl(CvWindow* window)
    {
        CV_FUNCNAME( "drawGl" );

        __BEGIN__;

        if (!wglMakeCurrent(window->dc, window->hGLRC))
            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (window->glDrawCallback)
            window->glDrawCallback(window->glDrawData);

        if (!SwapBuffers(window->dc))
            CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );

        __END__;
    }

    void resizeGl(CvWindow* window)
    {
        CV_FUNCNAME( "resizeGl" );

        __BEGIN__;

        if (!wglMakeCurrent(window->dc, window->hGLRC))
            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );

        glViewport(0, 0, window->width, window->height);

        __END__;
    }
}

#endif // HAVE_OPENGL


CV_IMPL int cvNamedWindow( const char* name, int flags )
{
    int result = 0;
    CV_FUNCNAME( "cvNamedWindow" );

    __BEGIN__;

    HWND hWnd, mainhWnd;
    CvWindow* window;
    DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
    int len;
    CvRect rect;
#ifdef HAVE_OPENGL
    bool useGl;
    HDC hGLDC;
    HGLRC hGLRC;
#endif

    cvInitSystem(0,0);

    if( !name )
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    // Check the name in the storage
    window = icvFindWindowByName( name );
    if (window != 0)
    {
        result = 1;
        EXIT;
    }

    if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
       defStyle |= WS_SIZEBOX;

#ifdef HAVE_OPENGL
    if (flags & CV_WINDOW_OPENGL)
        defStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
#endif

    icvLoadWindowPos( name, rect );

    mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
                             rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
    if( !mainhWnd )
        CV_ERROR( CV_StsError, "Frame window can not be created" );

    ShowWindow(mainhWnd, SW_SHOW);

    //YV- remove one border by changing the style
    hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
    if( !hWnd )
        CV_ERROR( CV_StsError, "Frame window can not be created" );

#ifndef HAVE_OPENGL
    if (flags & CV_WINDOW_OPENGL)
        CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
#else
    useGl = false;
    hGLDC = 0;
    hGLRC = 0;

    if (flags & CV_WINDOW_OPENGL)
        createGlContext(hWnd, hGLDC, hGLRC, useGl);
#endif

    ShowWindow(hWnd, SW_SHOW);

    len = (int)strlen(name);
    CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));

    window->signature = CV_WINDOW_MAGIC_VAL;
    window->hwnd = hWnd;
    window->frame = mainhWnd;
    window->name = (char*)(window + 1);
    memcpy( window->name, name, len + 1 );
    window->flags = flags;
    window->image = 0;

#ifndef HAVE_OPENGL
    window->dc = CreateCompatibleDC(0);
#else
    if (!useGl)
    {
        window->dc = CreateCompatibleDC(0);
        window->hGLRC = 0;
        window->useGl = false;
    }
    else
    {
        window->dc = hGLDC;
        window->hGLRC = hGLRC;
        window->useGl = true;
    }

    window->glDrawCallback = 0;
    window->glDrawData = 0;
#endif

    window->last_key = 0;
    window->status = CV_WINDOW_NORMAL;//YV

    window->on_mouse = 0;
    window->on_mouse_param = 0;

    memset( &window->toolbar, 0, sizeof(window->toolbar));

    window->next = hg_windows;
    window->prev = 0;
    if( hg_windows )
        hg_windows->prev = window;
    hg_windows = window;
    icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
    icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );

    // Recalculate window pos
    icvUpdateWindowPos( window );

    result = 1;
    __END__;

    return result;
}

#ifdef HAVE_OPENGL

CV_IMPL void cvSetOpenGlContext(const char* name)
{
    CV_FUNCNAME( "cvSetOpenGlContext" );

    __BEGIN__;

    CvWindow* window;

    if(!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        CV_ERROR( CV_StsNullPtr, "NULL window" );

    if (!window->useGl)
        CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );

    if (!wglMakeCurrent(window->dc, window->hGLRC))
        CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );

    __END__;
}

CV_IMPL void cvUpdateWindow(const char* name)
{
    CV_FUNCNAME( "cvUpdateWindow" );

    __BEGIN__;

    CvWindow* window;

    if (!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if (!window)
        EXIT;

    InvalidateRect(window->hwnd, 0, 0);

    __END__;
}

CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
{
    CV_FUNCNAME( "cvCreateOpenGLCallback" );

    __BEGIN__;

    CvWindow* window;

    if(!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if( !window )
        EXIT;

    if (!window->useGl)
        CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );

    window->glDrawCallback = callback;
    window->glDrawData = userdata;

    __END__;
}

#endif // HAVE_OPENGL

static void icvRemoveWindow( CvWindow* window )
{
    CvTrackbar* trackbar = NULL;
    RECT wrect={0,0,0,0};

#ifdef HAVE_OPENGL
    if (window->useGl)
        releaseGlContext(window);
#endif

    if( window->frame )
        GetWindowRect( window->frame, &wrect );
    if( window->name )
        icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
            wrect.right-wrect.left, wrect.bottom-wrect.top) );

    if( window->hwnd )
        icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
    if( window->frame )
        icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );

    if( window->toolbar.toolbar )
        icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);

    if( window->prev )
        window->prev->next = window->next;
    else
        hg_windows = window->next;

    if( window->next )
        window->next->prev = window->prev;

    window->prev = window->next = 0;

    if( window->dc && window->image )
        DeleteObject(SelectObject(window->dc,window->image));

    if( window->dc )
        DeleteDC(window->dc);

    for( trackbar = window->toolbar.first; trackbar != 0; )
    {
        CvTrackbar* next = trackbar->next;
        if( trackbar->hwnd )
        {
            icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
            cvFree( &trackbar );
        }
        trackbar = next;
    }

    cvFree( &window );
}


CV_IMPL void cvDestroyWindow( const char* name )
{
    CV_FUNCNAME( "cvDestroyWindow" );

    __BEGIN__;

    CvWindow* window;
    HWND mainhWnd;

    if(!name)
        CV_ERROR( CV_StsNullPtr, "NULL name string" );

    window = icvFindWindowByName( name );
    if( !window )
        EXIT;

    mainhWnd = window->frame;

    SendMessage(window->hwnd, WM_CLOSE, 0, 0);
    SendMessage( mainhWnd, WM_CLOSE, 0, 0);
    // Do NOT call _remove_window -- CvWindow list will be updated automatically ...

    __END__;
}


static void icvScreenToClient( HWND hwnd, RECT* rect )
{
    POINT p;
    p.x = rect->left;
    p.y = rect->top;
    ScreenToClient(hwnd, &p);
    OffsetRect( rect, p.x - rect->left, p.y - rect->top );
}


/* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
static RECT icvCalcWindowRect( CvWindow* window )
{
    const int gutter = 1;
    RECT crect, trect, rect;

    assert(window);

    GetClientRect(window->frame, &crect);
    if(window->toolbar.toolbar)
    {
        GetWindowRect(window->toolbar.toolbar, &trect);
        icvScreenToClient(window->frame, &trect);
        SubtractRect( &rect, &crect, &trect);
    }
    else
        rect = crect;

    rect.top += gutter;
    rect.left += gutter;
    rect.bottom -= gutter;
    rect.right -= gutter;

    return rect;
}

// returns TRUE if there is a problem such as ERROR_IO_PENDING.
static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
{
    BITMAP bmp;
    GdiFlush();
    HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
    if( size )
        size->cx = size->cy = 0;
    if( data )
        *data = 0;

    if (h == NULL)
        return true;
    if (GetObject(h, sizeof(bmp), &bmp) == 0)
        return true;

    if( size )
    {
        size->cx = abs(bmp.bmWidth);
        size->cy = abs(bmp.bmHeight);
    }

    if( channels )
        *channels = bmp.bmBitsPixel/8;

    if( data )
        *data = bmp.bmBits;

    return false;
}


static void icvUpdateWindowPos( CvWindow* window )
{
    RECT rect;
    assert(window);

    if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
    {
        int i;
        SIZE size = {0,0};
        icvGetBitmapData( window, &size, 0, 0 );

        // Repeat two times because after the first resizing of the mainhWnd window
        // toolbar may resize too
        for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
        {
            RECT rmw, rw = icvCalcWindowRect(window );
            MoveWindow(window->hwnd, rw.left, rw.top,
                rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
            GetClientRect(window->hwnd, &rw);
            GetWindowRect(window->frame, &rmw);
            // Resize the mainhWnd window in order to make the bitmap fit into the child window
            MoveWindow(window->frame, rmw.left, rmw.top,
                rmw.right - rmw.left + size.cx - rw.right + rw.left,
                rmw.bottom  - rmw.top + size.cy - rw.bottom + rw.top, TRUE );
        }
    }

    rect = icvCalcWindowRect(window);
    MoveWindow(window->hwnd, rect.left, rect.top,
               rect.right - rect.left + 1,
               rect.bottom - rect.top + 1, TRUE );
}

CV_IMPL void
cvShowImage( const char* name, const CvArr* arr )
{
    CV_FUNCNAME( "cvShowImage" );

    __BEGIN__;

    CvWindow* window;
    SIZE size = { 0, 0 };
    int channels = 0;
    void* dst_ptr = 0;
    const int channels0 = 3;
    int origin = 0;
    CvMat stub, dst, *image;
    bool changed_size = false; // philipg

    if( !name )
        CV_ERROR( CV_StsNullPtr, "NULL name" );

    window = icvFindWindowByName(name);
    if(!window)
    {
        cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
        window = icvFindWindowByName(name);
    }

    if( !window || !arr )
        EXIT; // keep silence here.

    if( CV_IS_IMAGE_HDR( arr ))
        origin = ((IplImage*)arr)->origin;

    CV_CALL( image = cvGetMat( arr, &stub ));

#ifdef HAVE_OPENGL
    if (window->useGl)
    {
        cv::imshow(name, cv::cvarrToMat(image));
        return;
    }
#endif

    if (window->image)
        // if there is something wrong with these system calls, we cannot display image...
        if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
            return;

    if( size.cx != image->width || size.cy != image->height || channels != channels0 )
    {
        changed_size = true;

        uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
        BITMAPINFO* binfo = (BITMAPINFO*)buffer;

        DeleteObject( SelectObject( window->dc, window->image ));
        window->image = 0;

        size.cx = image->width;
        size.cy = image->height;
        channels = channels0;

        FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );

        window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
                                      DIB_RGB_COLORS, &dst_ptr, 0, 0));
    }

    cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
                     dst_ptr, (size.cx * channels + 3) & -4 );
    cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );

    // ony resize window if needed
    if (changed_size)
        icvUpdateWindowPos(window);
    InvalidateRect(window->hwnd, 0, 0);
    // philipg: this is not needed and just slows things down
    //    UpdateWindow(window->hwnd);

    __END__;
}

#if 0
CV_IMPL void
cvShowImageHWND(HWND w_hWnd, const CvArr* arr)
{
    CV_FUNCNAME( "cvShowImageHWND" );

    __BEGIN__;

    SIZE size = { 0, 0 };
    int channels = 0;
    void* dst_ptr = 0;
    const int channels0 = 3;
    int origin = 0;
    CvMat stub, dst, *image;
    bool changed_size = false;
    BITMAPINFO tempbinfo;
    HDC hdc = NULL;

    if( !arr )
        EXIT;
    if( !w_hWnd )
        EXIT;

    hdc = GetDC(w_hWnd);

    if( CV_IS_IMAGE_HDR( arr ) )
        origin = ((IplImage*)arr)->origin;

    CV_CALL( image = cvGetMat( arr, &stub ) );

    if ( hdc )
    {
            //GetBitmapData
            BITMAP bmp;
            GdiFlush();
            HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );

            if (h == NULL)
            EXIT;
            if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
            EXIT;

            channels = bmp.bmBitsPixel/8;
            dst_ptr = bmp.bmBits;
     }

    if( size.cx != image->width || size.cy != image->height || channels != channels0 )
    {
        changed_size = true;

        uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
        BITMAPINFO* binfo = (BITMAPINFO*)buffer;

        BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
                CV_Assert( FALSE != bDeleteObj );

        size.cx = image->width;
        size.cy = image->height;
        channels = channels0;

        FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );

        SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
    }

    cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
    cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );

    // Image stretching to fit the window
    RECT rect;
    GetClientRect(w_hWnd, &rect);
    StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, &tempbinfo, DIB_RGB_COLORS, SRCCOPY );

    // ony resize window if needed
    InvalidateRect(w_hWnd, 0, 0);

    __END__;
}
#endif

CV_IMPL void cvResizeWindow(const char* name, int width, int height )
{
    CV_FUNCNAME( "cvResizeWindow" );

    __BEGIN__;

    int i;
    CvWindow* window;
    RECT rmw, rw, rect;

    if( !name )
        CV_ERROR( CV_StsNullPtr, "NULL name" );

    window = icvFindWindowByName(name);
    if(!window)
        EXIT;

    // Repeat two times because after the first resizing of the mainhWnd window
    // toolbar may resize too
    for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
    {
        rw = icvCalcWindowRect(window);
        MoveWindow(window->hwnd, rw.left, rw.top,
            rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
        GetClientRect(window->hwnd, &rw);
        GetWindowRect(window->frame, &rmw);
        // Resize the mainhWnd window in order to make the bitmap fit into the child window
        MoveWindow(window->frame, rmw.left, rmw.top,
            rmw.right - rmw.left + width - rw.right + rw.left,
            rmw.bottom  - rmw.top + height - rw.bottom + rw.top, TRUE);
    }

    rect = icvCalcWindowRect(window);
    MoveWindow(window->hwnd, rect.left, rect.top,
        rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE);

    __END__;
}


CV_IMPL void cvMoveWindow( const char* name, int x, int y )
{
    CV_FUNCNAME( "cvMoveWindow" );

    __BEGIN__;

    CvWindow* window;
    RECT rect;

    if( !name )
        CV_ERROR( CV_StsNullPtr, "NULL name" );

    window = icvFindWindowByName(name);
    if(!window)
        EXIT;

    GetWindowRect( window->frame, &rect );
    MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);

    __END__;
}


static LRESULT CALLBACK
MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    CvWindow* window = icvWindowByHWND( hwnd );
    if( !window )
        return DefWindowProc(hwnd, uMsg, wParam, lParam);

    switch(uMsg)
    {
    case WM_COPY:
        ::SendMessage(window->hwnd, uMsg, wParam, lParam);
        break;

    case WM_DESTROY:

        icvRemoveWindow(window);
        // Do nothing!!!
        //PostQuitMessage(0);
        break;

    case WM_GETMINMAXINFO:
        if( !(window->flags & CV_WINDOW_AUTOSIZE) )
        {
            MINMAXINFO* minmax = (MINMAXINFO*)lParam;
            RECT rect;
            LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);

            minmax->ptMinTrackSize.y = 100;
            minmax->ptMinTrackSize.x = 100;

            if( window->toolbar.first )
            {
                GetWindowRect( window->toolbar.first->hwnd, &rect );
                minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
                minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
            }
            return retval;
        }
        break;

    case WM_WINDOWPOSCHANGED:
        {
            WINDOWPOS* pos = (WINDOWPOS*)lParam;

            // Update the toolbar pos/size
            if(window->toolbar.toolbar)
            {
                RECT rect;
                GetWindowRect(window->toolbar.toolbar, &rect);
                MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
            }

            if(!(window->flags & CV_WINDOW_AUTOSIZE))
                icvUpdateWindowPos(window);

            break;
        }

    case WM_WINDOWPOSCHANGING:
       {
          // Snap window to screen edges with multi-monitor support. // Adi Shavit
          LPWINDOWPOS pos = (LPWINDOWPOS)lParam;

          RECT rect;
          GetWindowRect(window->frame, &rect);

          HMONITOR hMonitor;
          hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);

          MONITORINFO mi;
          mi.cbSize = sizeof(mi);
          GetMonitorInfo(hMonitor, &mi);

          const int SNAP_DISTANCE = 15;

          if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
             pos->x = mi.rcMonitor.left;               // snap to left edge
          else
             if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
                pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge

          if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
             pos->y = mi.rcMonitor.top;                 // snap to top edge
          else
             if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
                pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
       }

    case WM_ACTIVATE:
        if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
            SetFocus(window->hwnd);
        break;

    case WM_MOUSEWHEEL:
    case WM_MOUSEHWHEEL:
       if( window->on_mouse )
       {
          int flags = (wParam & MK_LBUTTON      ? CV_EVENT_FLAG_LBUTTON  : 0)|
                      (wParam & MK_RBUTTON      ? CV_EVENT_FLAG_RBUTTON  : 0)|
                      (wParam & MK_MBUTTON      ? CV_EVENT_FLAG_MBUTTON  : 0)|
                      (wParam & MK_CONTROL      ? CV_EVENT_FLAG_CTRLKEY  : 0)|
                      (wParam & MK_SHIFT        ? CV_EVENT_FLAG_SHIFTKEY : 0)|
                      (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY   : 0);
          int event = (uMsg == WM_MOUSEWHEEL    ? CV_EVENT_MOUSEWHEEL    : CV_EVENT_MOUSEHWHEEL);

          // Set the wheel delta of mouse wheel to be in the upper word of 'event'
          int delta = GET_WHEEL_DELTA_WPARAM(wParam);
          flags |= (delta << 16);

          POINT pt;
          pt.x = GET_X_LPARAM( lParam );
          pt.y = GET_Y_LPARAM( lParam );
          ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.

          RECT rect;
          GetClientRect( window->hwnd, &rect );

          SIZE size = {0,0};
          icvGetBitmapData( window, &size, 0, 0 );

          window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
                                   pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
                                   window->on_mouse_param );
       }
       break;

    case WM_ERASEBKGND:
        {
            RECT cr, tr, wrc;
            HRGN rgn, rgn1, rgn2;
            int ret;
            HDC hdc = (HDC)wParam;
            GetWindowRect(window->hwnd, &cr);
            icvScreenToClient(window->frame, &cr);
            if(window->toolbar.toolbar)
            {
                GetWindowRect(window->toolbar.toolbar, &tr);
                icvScreenToClient(window->frame, &tr);
            }
            else
                tr.left = tr.top = tr.right = tr.bottom = 0;

            GetClientRect(window->frame, &wrc);

            rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
            rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
            rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
            ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
            ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);

            if(ret != NULLREGION && ret != ERROR)
                FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));

            DeleteObject(rgn);
            DeleteObject(rgn1);
            DeleteObject(rgn2);
        }
        return 1;
    }

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


static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    CvWindow* window = icvWindowByHWND(hwnd);
    if( !window )
        // This window is not mentioned in HighGUI storage
        // Actually, this should be error except for the case of calls to CreateWindow
        return DefWindowProc(hwnd, uMsg, wParam, lParam);

    // Process the message
    switch(uMsg)
    {
    case WM_COPY:
        {
            if (!::OpenClipboard(hwnd) )
                break;

            HDC hDC       = 0;
            HDC memDC     = 0;
            HBITMAP memBM = 0;

            // We'll use a do-while(0){} scope as a single-run breakable scope
            // Upon any error we can jump out of the single-time while scope to clean up the resources.
            do
            {
                if (!::EmptyClipboard())
                    break;

                if(!window->image)
                    break;

                // Get window device context
                if (0 == (hDC = ::GetDC(hwnd)))
                    break;

                // Create another DC compatible with hDC
                if (0 == (memDC = ::CreateCompatibleDC( hDC )))
                    break;

                // Determine the bitmap's dimensions
                int nchannels = 3;
                SIZE size = {0,0};
                icvGetBitmapData( window, &size, &nchannels, 0 );

                // Create bitmap to draw on and it in the new DC
                if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
                    break;

                if (!::SelectObject( memDC, memBM ))
                    break;

                // Begin drawing to DC
                if (!::SetStretchBltMode(memDC, COLORONCOLOR))
                    break;

                RGBQUAD table[256];
                if( 1 == nchannels )
                {
                    for(int i = 0; i < 256; ++i)
                    {
                        table[i].rgbBlue = (unsigned char)i;
                        table[i].rgbGreen = (unsigned char)i;
                        table[i].rgbRed = (unsigned char)i;
                    }
                    if (!::SetDIBColorTable(window->dc, 0, 255, table))
                        break;
                }

                // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.

                // Render the image to the dc/bitmap (at original size).
                if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ))
                    break;

                // Finally, set bitmap to clipboard
                ::SetClipboardData(CF_BITMAP, memBM);
            } while (0,0); // (0,0) instead of (0) to avoid MSVC compiler warning C4127: "conditional expression is constant"

            //////////////////////////////////////////////////////////////////////////
            // if handle is allocated (i.e. != 0) then clean-up.
            if (memBM) ::DeleteObject(memBM);
            if (memDC) ::DeleteDC(memDC);
            if (hDC)   ::ReleaseDC(hwnd, hDC);
            ::CloseClipboard();
            break;
        }

    case WM_WINDOWPOSCHANGING:
        {
            LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
            RECT rect = icvCalcWindowRect(window);
            pos->x = rect.left;
            pos->y = rect.top;
            pos->cx = rect.right - rect.left + 1;
            pos->cy = rect.bottom - rect.top + 1;
        }
        break;

    case WM_LBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_LBUTTONDBLCLK:
    case WM_RBUTTONDBLCLK:
    case WM_MBUTTONDBLCLK:
    case WM_LBUTTONUP:
    case WM_RBUTTONUP:
    case WM_MBUTTONUP:
    case WM_MOUSEMOVE:
        if( window->on_mouse )
        {
            POINT pt;

            int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
                        (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
                        (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
                        (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
                        (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
                        (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
            int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
                        uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
                        uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
                        uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
                        uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
                        uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
                        uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
                        uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
                        uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
                                                   CV_EVENT_MOUSEMOVE;
            if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
                SetCapture( hwnd );
            if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
                ReleaseCapture();

            pt.x = GET_X_LPARAM( lParam );
            pt.y = GET_Y_LPARAM( lParam );

            if (window->flags & CV_WINDOW_AUTOSIZE)
            {
                // As user can't change window size, do not scale window coordinates. Underlying windowing system
                // may prevent full window from being displayed and in this case coordinates should not be scaled.
                window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param );
            } else {
                // Full window is displayed using different size. Scale coordinates to match underlying positions.
                RECT rect;
                SIZE size = {0, 0};

                GetClientRect( window->hwnd, &rect );
                icvGetBitmapData( window, &size, 0, 0 );

                window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
                                         pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
                                         window->on_mouse_param );
            }
        }
        break;

    case WM_PAINT:
        if(window->image != 0)
        {
            int nchannels = 3;
            SIZE size = {0,0};
            PAINTSTRUCT paint;
            HDC hdc;
            RGBQUAD table[256];

            // Determine the bitmap's dimensions
            icvGetBitmapData( window, &size, &nchannels, 0 );

            hdc = BeginPaint(hwnd, &paint);
            SetStretchBltMode(hdc, COLORONCOLOR);

            if( nchannels == 1 )
            {
                int i;
                for(i = 0; i < 256; i++)
                {
                    table[i].rgbBlue = (unsigned char)i;
                    table[i].rgbGreen = (unsigned char)i;
                    table[i].rgbRed = (unsigned char)i;
                }
                SetDIBColorTable(window->dc, 0, 255, table);
            }

            if(window->flags & CV_WINDOW_AUTOSIZE)
            {
                BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
            }
            else
            {
                RECT rect;
                GetClientRect(window->hwnd, &rect);
                StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
                            window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
            }
            //DeleteDC(hdc);
            EndPaint(hwnd, &paint);
        }
#ifdef HAVE_OPENGL
        else if(window->useGl)
        {
            drawGl(window);
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
#endif
        else
        {
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        return 0;

    case WM_ERASEBKGND:
        if(window->image)
            return 0;
        break;

    case WM_DESTROY:

        icvRemoveWindow(window);
        // Do nothing!!!
        //PostQuitMessage(0);
        break;

    case WM_SETCURSOR:
        SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
        return 0;

    case WM_KEYDOWN:
        window->last_key = (int)wParam;
        return 0;

    case WM_SIZE:
        window->width = LOWORD(lParam);
        window->height = HIWORD(lParam);

#ifdef HAVE_OPENGL
        if (window->useGl)
            resizeGl(window);
#endif
    }

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


static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    LRESULT ret;

    if( hg_on_preprocess )
    {
        int was_processed = 0;
        int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
        if( was_processed )
            return rethg;
    }
    ret = HighGUIProc(hwnd, uMsg, wParam, lParam);

    if(hg_on_postprocess)
    {
        int was_processed = 0;
        int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
        if( was_processed )
            return rethg;
    }

    return ret;
}


static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
{
    const int max_name_len = 10;
    const char* suffix = "";
    char pos_text[32];
    int name_len;

    if( trackbar->data )
        *trackbar->data = pos;

    if( trackbar->pos != pos )
    {
        trackbar->pos = pos;
        if( trackbar->notify2 )
            trackbar->notify2(pos, trackbar->userdata);
        if( trackbar->notify )
            trackbar->notify(pos);

        name_len = (int)strlen(trackbar->name);

        if( name_len > max_name_len )
        {
            int start_len = max_name_len*2/3;
            int end_len = max_name_len - start_len - 2;
            memcpy( pos_text, trackbar->name, start_len );
            memcpy( pos_text + start_len, "...", 3 );
            memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
        }
        else
        {
            memcpy( pos_text, trackbar->name, name_len + 1);
        }

        sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
        SetWindowText( trackbar->buddy, pos_text );
    }
}


static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    CvWindow* window = icvWindowByHWND( hwnd );
    if(!window)
        return DefWindowProc(hwnd, uMsg, wParam, lParam);

    // Control messages processing
    switch(uMsg)
    {
    // Slider processing
    case WM_HSCROLL:
        {
            HWND slider = (HWND)lParam;
            int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
            CvTrackbar* trackbar = icvTrackbarByHWND( slider );

            if( trackbar )
            {
                if( trackbar->pos != pos )
                    icvUpdateTrackbar( trackbar, pos );
            }

            SetFocus( window->hwnd );
            return 0;
        }

    case WM_NCCALCSIZE:
        {
            LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
            int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);

            if(window->toolbar.rows != rows)
            {
                SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
                CvTrackbar* trackbar = window->toolbar.first;

                for( ; trackbar != 0; trackbar = trackbar->next )
                {
                    RECT rect;
                    SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
                               (WPARAM)trackbar->id, (LPARAM)&rect);
                    MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
                               rect.right - rect.left - HG_BUDDY_WIDTH,
                               rect.bottom - rect.top, FALSE);
                    MoveWindow(trackbar->buddy, rect.left, rect.top,
                               HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
                }
                window->toolbar.rows = rows;
            }
            return ret;
        }
    }

    return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
}


CV_IMPL void
cvDestroyAllWindows(void)
{
    CvWindow* window = hg_windows;

    while( window )
    {
        HWND mainhWnd = window->frame;
        HWND hwnd = window->hwnd;
        window = window->next;

        SendMessage( hwnd, WM_CLOSE, 0, 0 );
        SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
    }
}

static void showSaveDialog(CvWindow* window)
{
    if (!window || !window->image)
        return;

    SIZE sz;
    int channels;
    void* data;
    if (icvGetBitmapData(window, &sz, &channels, &data))
        return; // nothing to save

    char szFileName[MAX_PATH] = "";
    // try to use window title as file name
    GetWindowText(window->frame, szFileName, MAX_PATH);

    OPENFILENAME ofn;
    ZeroMemory(&ofn, sizeof(ofn));
#ifdef OPENFILENAME_SIZE_VERSION_400
    // we are not going to use new fields any way
    ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
#else
    ofn.lStructSize = sizeof(ofn);
#endif
    ofn.hwndOwner = window->hwnd;
    ofn.lpstrFilter = "Portable Network Graphics files (*.png)\0*.png\0"
                      "JPEG files (*.jpeg;*.jpg;*.jpe)\0*.jpeg;*.jpg;*.jpe\0"
                      "Windows bitmap (*.bmp;*.dib)\0*.bmp;*.dib\0"
                      "TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
                      "JPEG-2000 files (*.jp2)\0*.jp2\0"
                      "WebP files (*.webp)\0*.webp\0"
                      "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)\0*.pbm;*.pgm;*.ppm;*.pxm;*.pnm\0"
                      "OpenEXR Image files (*.exr)\0*.exr\0"
                      "Radiance HDR (*.hdr;*.pic)\0*.hdr;*.pic\0"
                      "Sun raster files (*.sr;*.ras)\0*.sr;*.ras\0"
                      "All Files (*.*)\0*.*\0";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_NOCHANGEDIR;
    ofn.lpstrDefExt = "png";

    if (GetSaveFileName(&ofn))
    {
        cv::Mat tmp; cv::flip(cv::Mat(sz.cy, sz.cx, CV_8UC(channels), data), tmp, 0);
        cv::imwrite(szFileName, tmp);
    }
}

CV_IMPL int
cvWaitKey( int delay )
{
    int time0 = GetTickCount();

    for(;;)
    {
        CvWindow* window;
        MSG message;
        int is_processed = 0;

        if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
            return -1;

        if( delay <= 0 )
            GetMessage(&message, 0, 0, 0);
        else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
        {
            Sleep(1);
            continue;
        }

        for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
        {
            if( window->hwnd == message.hwnd || window->frame == message.hwnd )
            {
                is_processed = 1;
                switch(message.message)
                {
                case WM_DESTROY:
                case WM_CHAR:
                    DispatchMessage(&message);
                    return (int)message.wParam;

                case WM_SYSKEYDOWN:
                    if( message.wParam == VK_F10 )
                    {
                        is_processed = 1;
                        return (int)(message.wParam << 16);
                    }
                    break;

                case WM_KEYDOWN:
                    TranslateMessage(&message);
                    if( (message.wParam >= VK_F1 && message.wParam <= VK_F24)       ||
                        message.wParam == VK_HOME   || message.wParam == VK_END     ||
                        message.wParam == VK_UP     || message.wParam == VK_DOWN    ||
                        message.wParam == VK_LEFT   || message.wParam == VK_RIGHT   ||
                        message.wParam == VK_INSERT || message.wParam == VK_DELETE  ||
                        message.wParam == VK_PRIOR  || message.wParam == VK_NEXT )
                    {
                        DispatchMessage(&message);
                        is_processed = 1;
                        return (int)(message.wParam << 16);
                    }

                    // Intercept Ctrl+C for copy to clipboard
                    if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
                        ::SendMessage(message.hwnd, WM_COPY, 0, 0);

                    // Intercept Ctrl+S for "save as" dialog
                    if ('S' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
                        showSaveDialog(window);

                default:
                    DispatchMessage(&message);
                    is_processed = 1;
                    break;
                }
            }
        }

        if( !is_processed )
        {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }
    }
}


static CvTrackbar*
icvFindTrackbarByName( const CvWindow* window, const char* name )
{
    CvTrackbar* trackbar = window->toolbar.first;

    for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
        ;

    return trackbar;
}


static int
icvCreateTrackbar( const char* trackbar_name, const char* window_name,
                   int* val, int count, CvTrackbarCallback on_notify,
                   CvTrackbarCallback2 on_notify2, void* userdata )
{
    int result = 0;

    CV_FUNCNAME( "icvCreateTrackbar" );

    __BEGIN__;

    char slider_name[32];
    CvWindow* window = 0;
    CvTrackbar* trackbar = 0;
    int pos = 0;

    if( !window_name || !trackbar_name )
        CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );

    if( count < 0 )
        CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );

    window = icvFindWindowByName(window_name);
    if( !window )
        EXIT;

    trackbar = icvFindTrackbarByName(window,trackbar_name);
    if( !trackbar )
    {
        TBBUTTON tbs = {0};
        TBBUTTONINFO tbis = {0};
        RECT rect;
        int bcount;
        int len = (int)strlen( trackbar_name );

        // create toolbar if it is not created yet
        if( !window->toolbar.toolbar )
        {
            const int default_height = 30;

            // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
            window->toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
                                        WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
                                        0, 0, 0, 0,
                                        window->frame, NULL, GetModuleHandle(NULL), NULL);
            // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
            SendMessage(window->toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);

            GetClientRect(window->frame, &rect);
            MoveWindow( window->toolbar.toolbar, 0, 0,
                        rect.right - rect.left, default_height, TRUE);
            SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
            ShowWindow(window->toolbar.toolbar, SW_SHOW);

            window->toolbar.first = 0;
            window->toolbar.pos = 0;
            window->toolbar.rows = 0;
            window->toolbar.toolBarProc =
                (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);

            icvUpdateWindowPos(window);

            // Subclassing from toolbar
            icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
            icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
        }

        /* Retrieve current buttons count */
        bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);

        if(bcount > 1)
        {
            /* If this is not the first button then we need to
            separate it from the previous one */
            tbs.iBitmap = 0;
            tbs.idCommand = bcount; // Set button id to it's number
            tbs.iString = 0;
            tbs.fsStyle = TBSTYLE_SEP;
            tbs.fsState = TBSTATE_ENABLED;
            SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);

            // Retrieve current buttons count
            bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
        }

        /* Add a button which we're going to cover with the slider */
        tbs.iBitmap = 0;
        tbs.idCommand = bcount; // Set button id to it's number
        tbs.fsState = TBSTATE_ENABLED;
#if 0/*!defined WIN64 && !defined EM64T*/
        tbs.fsStyle = 0;
        tbs.iString = 0;
#else

#ifndef TBSTYLE_AUTOSIZE
#define TBSTYLE_AUTOSIZE        0x0010
#endif

#ifndef TBSTYLE_GROUP
#define TBSTYLE_GROUP           0x0004
#endif
        //tbs.fsStyle = TBSTYLE_AUTOSIZE;
        tbs.fsStyle = TBSTYLE_GROUP;
        tbs.iString = (INT_PTR)trackbar_text;
#endif
        SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);

        /* Adjust button size to the slider */
        tbis.cbSize = sizeof(tbis);
        tbis.dwMask = TBIF_SIZE;

        GetClientRect(window->hwnd, &rect);
        tbis.cx = (unsigned short)(rect.right - rect.left);

        SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
            (WPARAM)tbs.idCommand, (LPARAM)&tbis);

        /* Get button pos */
        SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
            (WPARAM)tbs.idCommand, (LPARAM)&rect);

        /* Create a slider */
        trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
        trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
        trackbar->notify = 0;
        trackbar->notify2 = 0;
        trackbar->parent = window;
        trackbar->pos = 0;
        trackbar->data = 0;
        trackbar->id = bcount;
        trackbar->next = window->toolbar.first;
        trackbar->name = (char*)(trackbar + 1);
        memcpy( trackbar->name, trackbar_name, len + 1 );
        window->toolbar.first = trackbar;

        sprintf(slider_name, "Trackbar%p", val);
        trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
                            WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
                            TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
                            rect.left + HG_BUDDY_WIDTH, rect.top,
                            rect.right - rect.left - HG_BUDDY_WIDTH,
                            rect.bottom - rect.top, window->toolbar.toolbar,
                            (HMENU)(size_t)bcount, hg_hinstance, 0);

        sprintf(slider_name,"Buddy%p", val);
        trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
                            WS_CHILD | SS_RIGHT,
                            rect.left, rect.top,
                            HG_BUDDY_WIDTH, rect.bottom - rect.top,
                            window->toolbar.toolbar, 0, hg_hinstance, 0);

        icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );

        /* Minimize the number of rows */
        SendMessage( window->toolbar.toolbar, TB_SETROWS,
                     MAKEWPARAM(1, FALSE), (LPARAM)&rect );
    }
    else
    {
        trackbar->data = 0;
        trackbar->notify = 0;
        trackbar->notify2 = 0;
    }

    trackbar->maxval = count;

    /* Adjust slider parameters */
    SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
    SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)count);
    SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
    if( val )
        pos = *val;

    SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
    SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);

    trackbar->pos = -1;
    icvUpdateTrackbar( trackbar, pos );
    ShowWindow( trackbar->buddy, SW_SHOW );
    ShowWindow( trackbar->hwnd, SW_SHOW );

    trackbar->notify = on_notify;
    trackbar->notify2 = on_notify2;
    trackbar->userdata = userdata;
    trackbar->data = val;

    /* Resize the window to reflect the toolbar resizing*/
    icvUpdateWindowPos(window);

    result = 1;

    __END__;

    return result;
}

CV_IMPL int
cvCreateTrackbar( const char* trackbar_name, const char* window_name,
                  int* val, int count, CvTrackbarCallback on_notify )
{
    return icvCreateTrackbar( trackbar_name, window_name, val, count,
        on_notify, 0, 0 );
}

CV_IMPL int
cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
                   int* val, int count, CvTrackbarCallback2 on_notify2,
                   void* userdata )
{
    return icvCreateTrackbar( trackbar_name, window_name, val, count,
        0, on_notify2, userdata );
}

CV_IMPL void
cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
{
    CV_FUNCNAME( "cvSetMouseCallback" );

    __BEGIN__;

    CvWindow* window = 0;

    if( !window_name )
        CV_ERROR( CV_StsNullPtr, "NULL window name" );

    window = icvFindWindowByName(window_name);
    if( !window )
        EXIT;

    window->on_mouse = on_mouse;
    window->on_mouse_param = param;

    __END__;
}


CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
{
    int pos = -1;

    CV_FUNCNAME( "cvGetTrackbarPos" );

    __BEGIN__;

    CvWindow* window;
    CvTrackbar* trackbar = 0;

    if( trackbar_name == 0 || window_name == 0 )
        CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );

    window = icvFindWindowByName( window_name );
    if( window )
        trackbar = icvFindTrackbarByName( window, trackbar_name );

    if( trackbar )
        pos = trackbar->pos;

    __END__;

    return pos;
}


CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
{
    CV_FUNCNAME( "cvSetTrackbarPos" );

    __BEGIN__;

    CvWindow* window;
    CvTrackbar* trackbar = 0;

    if( trackbar_name == 0 || window_name == 0 )
        CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );

    window = icvFindWindowByName( window_name );
    if( window )
        trackbar = icvFindTrackbarByName( window, trackbar_name );

    if( trackbar )
    {
        if( pos < 0 )
            pos = 0;

        if( pos > trackbar->maxval )
            pos = trackbar->maxval;

        SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
        icvUpdateTrackbar( trackbar, pos );
    }

    __END__;
}


CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
{
    CV_FUNCNAME( "cvSetTrackbarMax" );

    __BEGIN__;

    if (maxval >= 0)
    {
        CvWindow* window = 0;
        CvTrackbar* trackbar = 0;
        if (trackbar_name == 0 || window_name == 0)
        {
            CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
        }

        window = icvFindWindowByName(window_name);
        if (window)
        {
            trackbar = icvFindTrackbarByName(window, trackbar_name);
            if (trackbar)
            {
                // The position will be min(pos, maxval).
                trackbar->maxval = maxval;
                SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
            }
        }
    }

    __END__;
}


CV_IMPL void* cvGetWindowHandle( const char* window_name )
{
    void* hwnd = 0;

    CV_FUNCNAME( "cvGetWindowHandle" );

    __BEGIN__;

    CvWindow* window;

    if( window_name == 0 )
        CV_ERROR( CV_StsNullPtr, "NULL window name" );

    window = icvFindWindowByName( window_name );
    if( window )
        hwnd = (void*)window->hwnd;

    __END__;

    return hwnd;
}


CV_IMPL const char* cvGetWindowName( void* window_handle )
{
    const char* window_name = "";

    CV_FUNCNAME( "cvGetWindowName" );

    __BEGIN__;

    CvWindow* window;

    if( window_handle == 0 )
        CV_ERROR( CV_StsNullPtr, "NULL window" );

    window = icvWindowByHWND( (HWND)window_handle );
    if( window )
        window_name = window->name;

    __END__;

    return window_name;
}


CV_IMPL void
cvSetPreprocessFuncWin32_(const void* callback)
{
    hg_on_preprocess = (CvWin32WindowCallback)callback;
}

CV_IMPL void
cvSetPostprocessFuncWin32_(const void* callback)
{
    hg_on_postprocess = (CvWin32WindowCallback)callback;
}

#endif //WIN32

/* [<][>][^][v][top][bottom][index][help] */