Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "precomp.hpp"
     43 #include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros
     44 
     45 #if defined WIN32 || defined _WIN32
     46 
     47 #ifdef __GNUC__
     48 #  pragma GCC diagnostic ignored "-Wmissing-declarations"
     49 #endif
     50 
     51 #if (_WIN32_IE < 0x0500)
     52 #pragma message("WARNING: Win32 UI needs to be compiled with _WIN32_IE >= 0x0500 (_WIN32_IE_IE50)")
     53 #define _WIN32_IE 0x0500
     54 #endif
     55 
     56 #include <commctrl.h>
     57 #include <stdlib.h>
     58 #include <string.h>
     59 #include <stdio.h>
     60 #include <assert.h>
     61 
     62 #ifdef HAVE_OPENGL
     63 #include <memory>
     64 #include <algorithm>
     65 #include <vector>
     66 #include <functional>
     67 #include "opencv2/highgui.hpp"
     68 #include <GL\gl.h>
     69 #endif
     70 
     71 static const char* trackbar_text =
     72 "                                                                                             ";
     73 
     74 #if defined _M_X64 || defined __x86_64
     75 
     76 #define icvGetWindowLongPtr GetWindowLongPtr
     77 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
     78 #define icvGetClassLongPtr  GetClassLongPtr
     79 
     80 #define CV_USERDATA GWLP_USERDATA
     81 #define CV_WNDPROC GWLP_WNDPROC
     82 #define CV_HCURSOR GCLP_HCURSOR
     83 #define CV_HBRBACKGROUND GCLP_HBRBACKGROUND
     84 
     85 #else
     86 
     87 #define icvGetWindowLongPtr GetWindowLong
     88 #define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
     89 #define icvGetClassLongPtr GetClassLong
     90 
     91 #define CV_USERDATA GWL_USERDATA
     92 #define CV_WNDPROC GWL_WNDPROC
     93 #define CV_HCURSOR GCL_HCURSOR
     94 #define CV_HBRBACKGROUND GCL_HBRBACKGROUND
     95 
     96 #endif
     97 
     98 #ifndef WM_MOUSEHWHEEL
     99     #define WM_MOUSEHWHEEL 0x020E
    100 #endif
    101 
    102 static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
    103 {
    104     assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
    105 
    106     BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
    107 
    108     memset( bmih, 0, sizeof(*bmih));
    109     bmih->biSize = sizeof(BITMAPINFOHEADER);
    110     bmih->biWidth = width;
    111     bmih->biHeight = origin ? abs(height) : -abs(height);
    112     bmih->biPlanes = 1;
    113     bmih->biBitCount = (unsigned short)bpp;
    114     bmih->biCompression = BI_RGB;
    115 
    116     if( bpp == 8 )
    117     {
    118         RGBQUAD* palette = bmi->bmiColors;
    119         int i;
    120         for( i = 0; i < 256; i++ )
    121         {
    122             palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
    123             palette[i].rgbReserved = 0;
    124         }
    125     }
    126 }
    127 
    128 struct CvWindow;
    129 
    130 typedef struct CvTrackbar
    131 {
    132     int signature;
    133     HWND hwnd;
    134     char* name;
    135     CvTrackbar* next;
    136     CvWindow* parent;
    137     HWND buddy;
    138     int* data;
    139     int pos;
    140     int maxval;
    141     void (*notify)(int);
    142     void (*notify2)(int, void*);
    143     void* userdata;
    144     int id;
    145 }
    146 CvTrackbar;
    147 
    148 
    149 typedef struct CvWindow
    150 {
    151     int signature;
    152     HWND hwnd;
    153     char* name;
    154     CvWindow* prev;
    155     CvWindow* next;
    156     HWND frame;
    157 
    158     HDC dc;
    159     HGDIOBJ image;
    160     int last_key;
    161     int flags;
    162     int status;//0 normal, 1 fullscreen (YV)
    163 
    164     CvMouseCallback on_mouse;
    165     void* on_mouse_param;
    166 
    167     struct
    168     {
    169         HWND toolbar;
    170         int pos;
    171         int rows;
    172         WNDPROC toolBarProc;
    173         CvTrackbar* first;
    174     }
    175     toolbar;
    176 
    177     int width;
    178     int height;
    179 
    180     // OpenGL support
    181 
    182 #ifdef HAVE_OPENGL
    183     bool useGl;
    184     HGLRC hGLRC;
    185 
    186     CvOpenGlDrawCallback glDrawCallback;
    187     void* glDrawData;
    188 #endif
    189 }
    190 CvWindow;
    191 
    192 #define HG_BUDDY_WIDTH  130
    193 
    194 #ifndef TBIF_SIZE
    195     #define TBIF_SIZE  0x40
    196 #endif
    197 
    198 #ifndef TB_SETBUTTONINFO
    199     #define TB_SETBUTTONINFO (WM_USER + 66)
    200 #endif
    201 
    202 #ifndef TBM_GETTOOLTIPS
    203     #define TBM_GETTOOLTIPS  (WM_USER + 30)
    204 #endif
    205 
    206 static LRESULT CALLBACK HighGUIProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    207 static LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    208 static LRESULT CALLBACK MainWindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    209 static void icvUpdateWindowPos( CvWindow* window );
    210 
    211 static CvWindow* hg_windows = 0;
    212 
    213 typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
    214 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
    215 static HINSTANCE hg_hinstance = 0;
    216 
    217 static const char* highGUIclassName = "HighGUI class";
    218 static const char* mainHighGUIclassName = "Main HighGUI class";
    219 
    220 static void icvCleanupHighgui()
    221 {
    222     cvDestroyAllWindows();
    223     UnregisterClass(highGUIclassName, hg_hinstance);
    224     UnregisterClass(mainHighGUIclassName, hg_hinstance);
    225 }
    226 
    227 CV_IMPL int cvInitSystem( int, char** )
    228 {
    229     static int wasInitialized = 0;
    230 
    231     // check initialization status
    232     if( !wasInitialized )
    233     {
    234         // Initialize the stogare
    235         hg_windows = 0;
    236 
    237         // Register the class
    238         WNDCLASS wndc;
    239         wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
    240         wndc.lpfnWndProc = WindowProc;
    241         wndc.cbClsExtra = 0;
    242         wndc.cbWndExtra = 0;
    243         wndc.hInstance = hg_hinstance;
    244         wndc.lpszClassName = highGUIclassName;
    245         wndc.lpszMenuName = highGUIclassName;
    246         wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
    247         wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
    248         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
    249 
    250         RegisterClass(&wndc);
    251 
    252         wndc.lpszClassName = mainHighGUIclassName;
    253         wndc.lpszMenuName = mainHighGUIclassName;
    254         wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
    255         wndc.lpfnWndProc = MainWindowProc;
    256 
    257         RegisterClass(&wndc);
    258         atexit( icvCleanupHighgui );
    259 
    260         wasInitialized = 1;
    261     }
    262 
    263     setlocale(LC_NUMERIC,"C");
    264 
    265     return 0;
    266 }
    267 
    268 CV_IMPL int cvStartWindowThread(){
    269     return 0;
    270 }
    271 
    272 static CvWindow* icvFindWindowByName( const char* name )
    273 {
    274     CvWindow* window = hg_windows;
    275 
    276     for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
    277         ;
    278 
    279     return window;
    280 }
    281 
    282 
    283 static CvWindow* icvWindowByHWND( HWND hwnd )
    284 {
    285     CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
    286     return window != 0 && hg_windows != 0 &&
    287            window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
    288 }
    289 
    290 
    291 static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
    292 {
    293     CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
    294     return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
    295            trackbar->hwnd == hwnd ? trackbar : 0;
    296 }
    297 
    298 
    299 static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
    300 
    301 // Window positions saving/loading added by Philip Gruebele.
    302 //<a href="mailto:pgruebele (at) cox.net">pgruebele (at) cox.net</a>
    303 // Restores the window position from the registry saved position.
    304 static void
    305 icvLoadWindowPos( const char* name, CvRect& rect )
    306 {
    307     HKEY hkey;
    308     char szKey[1024];
    309     strcpy( szKey, icvWindowPosRootKey );
    310     strcat( szKey, name );
    311 
    312     rect.x = rect.y = CW_USEDEFAULT;
    313     rect.width = rect.height = 320;
    314 
    315     if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
    316     {
    317         // Yes we are installed.
    318         DWORD dwType = 0;
    319         DWORD dwSize = sizeof(int);
    320 
    321         RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize);
    322         RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize);
    323         RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize);
    324         RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize);
    325 
    326         if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) )
    327             rect.x = 100;
    328         if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) )
    329             rect.y = 100;
    330 
    331         if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) )
    332             rect.width = 100;
    333         if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) )
    334             rect.height = 100;
    335 
    336         RegCloseKey(hkey);
    337     }
    338 }
    339 
    340 
    341 // Window positions saving/loading added by Philip Gruebele.
    342 //<a href="mailto:pgruebele (at) cox.net">pgruebele (at) cox.net</a>
    343 // philipg.  Saves the window position in the registry
    344 static void
    345 icvSaveWindowPos( const char* name, CvRect rect )
    346 {
    347     static const DWORD MAX_RECORD_COUNT = 100;
    348     HKEY hkey;
    349     char szKey[1024];
    350     char rootKey[1024];
    351     strcpy( szKey, icvWindowPosRootKey );
    352     strcat( szKey, name );
    353 
    354     if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
    355     {
    356         HKEY hroot;
    357         DWORD count = 0;
    358         FILETIME oldestTime = { UINT_MAX, UINT_MAX };
    359         char oldestKey[1024];
    360         char currentKey[1024];
    361 
    362         strcpy( rootKey, icvWindowPosRootKey );
    363         rootKey[strlen(rootKey)-1] = '\0';
    364         if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
    365             //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
    366             return;
    367 
    368         for(;;)
    369         {
    370             DWORD csize = sizeof(currentKey);
    371             FILETIME accesstime = { 0, 0 };
    372             LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
    373             if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
    374                 break;
    375             count++;
    376             if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
    377                 (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
    378                 oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
    379             {
    380                 oldestTime = accesstime;
    381                 strcpy( oldestKey, currentKey );
    382             }
    383         }
    384 
    385         if( count >= MAX_RECORD_COUNT )
    386             RegDeleteKey( hroot, oldestKey );
    387         RegCloseKey( hroot );
    388 
    389         if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
    390             return;
    391     }
    392     else
    393     {
    394         RegCloseKey( hkey );
    395         if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
    396             return;
    397     }
    398 
    399     RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x));
    400     RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y));
    401     RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width));
    402     RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height));
    403     RegCloseKey(hkey);
    404 }
    405 
    406 double cvGetModeWindow_W32(const char* name)//YV
    407 {
    408     double result = -1;
    409 
    410     CV_FUNCNAME( "cvGetModeWindow_W32" );
    411 
    412     __BEGIN__;
    413 
    414     CvWindow* window;
    415 
    416     if (!name)
    417         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    418 
    419     window = icvFindWindowByName( name );
    420     if (!window)
    421         EXIT; // keep silence here
    422 
    423     result = window->status;
    424 
    425     __END__;
    426     return result;
    427 }
    428 
    429 void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
    430 {
    431     CV_FUNCNAME( "cvSetModeWindow_W32" );
    432 
    433     __BEGIN__;
    434 
    435     CvWindow* window;
    436 
    437     if(!name)
    438         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    439 
    440     window = icvFindWindowByName( name );
    441     if( !window )
    442         CV_ERROR( CV_StsNullPtr, "NULL window" );
    443 
    444     if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
    445         EXIT;
    446 
    447     {
    448         DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
    449         CvRect position;
    450 
    451         if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
    452         {
    453             icvLoadWindowPos(window->name,position );
    454             SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
    455 
    456             SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
    457             window->status=CV_WINDOW_NORMAL;
    458 
    459             EXIT;
    460         }
    461 
    462         if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
    463         {
    464             //save dimension
    465             RECT rect;
    466             GetWindowRect(window->frame, &rect);
    467             CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
    468             icvSaveWindowPos(window->name,RectCV );
    469 
    470             //Look at coordinate for fullscreen
    471             HMONITOR hMonitor;
    472             MONITORINFO mi;
    473             hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
    474 
    475             mi.cbSize = sizeof(mi);
    476             GetMonitorInfo(hMonitor, &mi);
    477 
    478             //fullscreen
    479             position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top;
    480             position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top;
    481             SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);
    482 
    483             SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
    484             window->status=CV_WINDOW_FULLSCREEN;
    485 
    486             EXIT;
    487         }
    488     }
    489 
    490     __END__;
    491 }
    492 
    493 void cv::setWindowTitle(const String& winname, const String& title)
    494 {
    495     CvWindow* window = icvFindWindowByName(winname.c_str());
    496 
    497     if (!window)
    498     {
    499         namedWindow(winname);
    500         window = icvFindWindowByName(winname.c_str());
    501     }
    502 
    503     if (!window)
    504         CV_Error(Error::StsNullPtr, "NULL window");
    505 
    506     if (!SetWindowText(window->frame, title.c_str()))
    507         CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", winname.c_str(), title.c_str()));
    508 }
    509 
    510 double cvGetPropWindowAutoSize_W32(const char* name)
    511 {
    512     double result = -1;
    513 
    514     CV_FUNCNAME( "cvSetCloseCallback" );
    515 
    516     __BEGIN__;
    517 
    518     CvWindow* window;
    519 
    520     if (!name)
    521         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    522 
    523     window = icvFindWindowByName( name );
    524     if (!window)
    525         EXIT; // keep silence here
    526 
    527     result = window->flags & CV_WINDOW_AUTOSIZE;
    528 
    529     __END__;
    530 
    531     return result;
    532 }
    533 
    534 double cvGetRatioWindow_W32(const char* name)
    535 {
    536     double result = -1;
    537 
    538     CV_FUNCNAME( "cvGetRatioWindow_W32" );
    539 
    540     __BEGIN__;
    541 
    542     CvWindow* window;
    543 
    544     if (!name)
    545         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    546 
    547     window = icvFindWindowByName( name );
    548     if (!window)
    549         EXIT; // keep silence here
    550 
    551     result = static_cast<double>(window->width) / window->height;
    552 
    553     __END__;
    554 
    555     return result;
    556 }
    557 
    558 double cvGetOpenGlProp_W32(const char* name)
    559 {
    560     double result = -1;
    561 
    562 #ifdef HAVE_OPENGL
    563     CV_FUNCNAME( "cvGetOpenGlProp_W32" );
    564 
    565     __BEGIN__;
    566 
    567     CvWindow* window;
    568 
    569     if (!name)
    570         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    571 
    572     window = icvFindWindowByName( name );
    573     if (!window)
    574         EXIT; // keep silence here
    575 
    576     result = window->useGl;
    577 
    578     __END__;
    579 #endif
    580     (void)name;
    581 
    582     return result;
    583 }
    584 
    585 
    586 // OpenGL support
    587 
    588 #ifdef HAVE_OPENGL
    589 
    590 namespace
    591 {
    592     void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
    593     {
    594         CV_FUNCNAME( "createGlContext" );
    595 
    596         __BEGIN__;
    597 
    598         useGl = false;
    599 
    600         int PixelFormat;
    601 
    602         static PIXELFORMATDESCRIPTOR pfd =
    603         {
    604             sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
    605             1,                             // Version Number
    606             PFD_DRAW_TO_WINDOW |           // Format Must Support Window
    607             PFD_SUPPORT_OPENGL |           // Format Must Support OpenGL
    608             PFD_DOUBLEBUFFER,              // Must Support Double Buffering
    609             PFD_TYPE_RGBA,                 // Request An RGBA Format
    610             32,                            // Select Our Color Depth
    611             0, 0, 0, 0, 0, 0,              // Color Bits Ignored
    612             0,                             // No Alpha Buffer
    613             0,                             // Shift Bit Ignored
    614             0,                             // No Accumulation Buffer
    615             0, 0, 0, 0,                    // Accumulation Bits Ignored
    616             32,                            // 32 Bit Z-Buffer (Depth Buffer)
    617             0,                             // No Stencil Buffer
    618             0,                             // No Auxiliary Buffer
    619             PFD_MAIN_PLANE,                // Main Drawing Layer
    620             0,                             // Reserved
    621             0, 0, 0                        // Layer Masks Ignored
    622         };
    623 
    624         hGLDC = GetDC(hWnd);
    625         if (!hGLDC)
    626             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
    627 
    628         PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
    629         if (!PixelFormat)
    630             CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );
    631 
    632         if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
    633             CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );
    634 
    635         hGLRC = wglCreateContext(hGLDC);
    636         if (!hGLRC)
    637             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );
    638 
    639         if (!wglMakeCurrent(hGLDC, hGLRC))
    640             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
    641 
    642         useGl = true;
    643 
    644         __END__;
    645     }
    646 
    647     void releaseGlContext(CvWindow* window)
    648     {
    649         //CV_FUNCNAME( "releaseGlContext" );
    650 
    651         __BEGIN__;
    652 
    653         if (window->hGLRC)
    654         {
    655             wglDeleteContext(window->hGLRC);
    656             window->hGLRC = NULL;
    657         }
    658 
    659         if (window->dc)
    660         {
    661             ReleaseDC(window->hwnd, window->dc);
    662             window->dc = NULL;
    663         }
    664 
    665         window->useGl = false;
    666 
    667         __END__;
    668     }
    669 
    670     void drawGl(CvWindow* window)
    671     {
    672         CV_FUNCNAME( "drawGl" );
    673 
    674         __BEGIN__;
    675 
    676         if (!wglMakeCurrent(window->dc, window->hGLRC))
    677             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
    678 
    679         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    680 
    681         if (window->glDrawCallback)
    682             window->glDrawCallback(window->glDrawData);
    683 
    684         if (!SwapBuffers(window->dc))
    685             CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );
    686 
    687         __END__;
    688     }
    689 
    690     void resizeGl(CvWindow* window)
    691     {
    692         CV_FUNCNAME( "resizeGl" );
    693 
    694         __BEGIN__;
    695 
    696         if (!wglMakeCurrent(window->dc, window->hGLRC))
    697             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
    698 
    699         glViewport(0, 0, window->width, window->height);
    700 
    701         __END__;
    702     }
    703 }
    704 
    705 #endif // HAVE_OPENGL
    706 
    707 
    708 CV_IMPL int cvNamedWindow( const char* name, int flags )
    709 {
    710     int result = 0;
    711     CV_FUNCNAME( "cvNamedWindow" );
    712 
    713     __BEGIN__;
    714 
    715     HWND hWnd, mainhWnd;
    716     CvWindow* window;
    717     DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
    718     int len;
    719     CvRect rect;
    720 #ifdef HAVE_OPENGL
    721     bool useGl;
    722     HDC hGLDC;
    723     HGLRC hGLRC;
    724 #endif
    725 
    726     cvInitSystem(0,0);
    727 
    728     if( !name )
    729         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    730 
    731     // Check the name in the storage
    732     window = icvFindWindowByName( name );
    733     if (window != 0)
    734     {
    735         result = 1;
    736         EXIT;
    737     }
    738 
    739     if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
    740        defStyle |= WS_SIZEBOX;
    741 
    742 #ifdef HAVE_OPENGL
    743     if (flags & CV_WINDOW_OPENGL)
    744         defStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
    745 #endif
    746 
    747     icvLoadWindowPos( name, rect );
    748 
    749     mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
    750                              rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
    751     if( !mainhWnd )
    752         CV_ERROR( CV_StsError, "Frame window can not be created" );
    753 
    754     ShowWindow(mainhWnd, SW_SHOW);
    755 
    756     //YV- remove one border by changing the style
    757     hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
    758     if( !hWnd )
    759         CV_ERROR( CV_StsError, "Frame window can not be created" );
    760 
    761 #ifndef HAVE_OPENGL
    762     if (flags & CV_WINDOW_OPENGL)
    763         CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
    764 #else
    765     useGl = false;
    766     hGLDC = 0;
    767     hGLRC = 0;
    768 
    769     if (flags & CV_WINDOW_OPENGL)
    770         createGlContext(hWnd, hGLDC, hGLRC, useGl);
    771 #endif
    772 
    773     ShowWindow(hWnd, SW_SHOW);
    774 
    775     len = (int)strlen(name);
    776     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
    777 
    778     window->signature = CV_WINDOW_MAGIC_VAL;
    779     window->hwnd = hWnd;
    780     window->frame = mainhWnd;
    781     window->name = (char*)(window + 1);
    782     memcpy( window->name, name, len + 1 );
    783     window->flags = flags;
    784     window->image = 0;
    785 
    786 #ifndef HAVE_OPENGL
    787     window->dc = CreateCompatibleDC(0);
    788 #else
    789     if (!useGl)
    790     {
    791         window->dc = CreateCompatibleDC(0);
    792         window->hGLRC = 0;
    793         window->useGl = false;
    794     }
    795     else
    796     {
    797         window->dc = hGLDC;
    798         window->hGLRC = hGLRC;
    799         window->useGl = true;
    800     }
    801 
    802     window->glDrawCallback = 0;
    803     window->glDrawData = 0;
    804 #endif
    805 
    806     window->last_key = 0;
    807     window->status = CV_WINDOW_NORMAL;//YV
    808 
    809     window->on_mouse = 0;
    810     window->on_mouse_param = 0;
    811 
    812     memset( &window->toolbar, 0, sizeof(window->toolbar));
    813 
    814     window->next = hg_windows;
    815     window->prev = 0;
    816     if( hg_windows )
    817         hg_windows->prev = window;
    818     hg_windows = window;
    819     icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
    820     icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
    821 
    822     // Recalculate window pos
    823     icvUpdateWindowPos( window );
    824 
    825     result = 1;
    826     __END__;
    827 
    828     return result;
    829 }
    830 
    831 #ifdef HAVE_OPENGL
    832 
    833 CV_IMPL void cvSetOpenGlContext(const char* name)
    834 {
    835     CV_FUNCNAME( "cvSetOpenGlContext" );
    836 
    837     __BEGIN__;
    838 
    839     CvWindow* window;
    840 
    841     if(!name)
    842         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    843 
    844     window = icvFindWindowByName( name );
    845     if (!window)
    846         CV_ERROR( CV_StsNullPtr, "NULL window" );
    847 
    848     if (!window->useGl)
    849         CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
    850 
    851     if (!wglMakeCurrent(window->dc, window->hGLRC))
    852         CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
    853 
    854     __END__;
    855 }
    856 
    857 CV_IMPL void cvUpdateWindow(const char* name)
    858 {
    859     CV_FUNCNAME( "cvUpdateWindow" );
    860 
    861     __BEGIN__;
    862 
    863     CvWindow* window;
    864 
    865     if (!name)
    866         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    867 
    868     window = icvFindWindowByName( name );
    869     if (!window)
    870         EXIT;
    871 
    872     InvalidateRect(window->hwnd, 0, 0);
    873 
    874     __END__;
    875 }
    876 
    877 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
    878 {
    879     CV_FUNCNAME( "cvCreateOpenGLCallback" );
    880 
    881     __BEGIN__;
    882 
    883     CvWindow* window;
    884 
    885     if(!name)
    886         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    887 
    888     window = icvFindWindowByName( name );
    889     if( !window )
    890         EXIT;
    891 
    892     if (!window->useGl)
    893         CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
    894 
    895     window->glDrawCallback = callback;
    896     window->glDrawData = userdata;
    897 
    898     __END__;
    899 }
    900 
    901 #endif // HAVE_OPENGL
    902 
    903 static void icvRemoveWindow( CvWindow* window )
    904 {
    905     CvTrackbar* trackbar = NULL;
    906     RECT wrect={0,0,0,0};
    907 
    908 #ifdef HAVE_OPENGL
    909     if (window->useGl)
    910         releaseGlContext(window);
    911 #endif
    912 
    913     if( window->frame )
    914         GetWindowRect( window->frame, &wrect );
    915     if( window->name )
    916         icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
    917             wrect.right-wrect.left, wrect.bottom-wrect.top) );
    918 
    919     if( window->hwnd )
    920         icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
    921     if( window->frame )
    922         icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
    923 
    924     if( window->toolbar.toolbar )
    925         icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);
    926 
    927     if( window->prev )
    928         window->prev->next = window->next;
    929     else
    930         hg_windows = window->next;
    931 
    932     if( window->next )
    933         window->next->prev = window->prev;
    934 
    935     window->prev = window->next = 0;
    936 
    937     if( window->dc && window->image )
    938         DeleteObject(SelectObject(window->dc,window->image));
    939 
    940     if( window->dc )
    941         DeleteDC(window->dc);
    942 
    943     for( trackbar = window->toolbar.first; trackbar != 0; )
    944     {
    945         CvTrackbar* next = trackbar->next;
    946         if( trackbar->hwnd )
    947         {
    948             icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
    949             cvFree( &trackbar );
    950         }
    951         trackbar = next;
    952     }
    953 
    954     cvFree( &window );
    955 }
    956 
    957 
    958 CV_IMPL void cvDestroyWindow( const char* name )
    959 {
    960     CV_FUNCNAME( "cvDestroyWindow" );
    961 
    962     __BEGIN__;
    963 
    964     CvWindow* window;
    965     HWND mainhWnd;
    966 
    967     if(!name)
    968         CV_ERROR( CV_StsNullPtr, "NULL name string" );
    969 
    970     window = icvFindWindowByName( name );
    971     if( !window )
    972         EXIT;
    973 
    974     mainhWnd = window->frame;
    975 
    976     SendMessage(window->hwnd, WM_CLOSE, 0, 0);
    977     SendMessage( mainhWnd, WM_CLOSE, 0, 0);
    978     // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
    979 
    980     __END__;
    981 }
    982 
    983 
    984 static void icvScreenToClient( HWND hwnd, RECT* rect )
    985 {
    986     POINT p;
    987     p.x = rect->left;
    988     p.y = rect->top;
    989     ScreenToClient(hwnd, &p);
    990     OffsetRect( rect, p.x - rect->left, p.y - rect->top );
    991 }
    992 
    993 
    994 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
    995 static RECT icvCalcWindowRect( CvWindow* window )
    996 {
    997     const int gutter = 1;
    998     RECT crect, trect, rect;
    999 
   1000     assert(window);
   1001 
   1002     GetClientRect(window->frame, &crect);
   1003     if(window->toolbar.toolbar)
   1004     {
   1005         GetWindowRect(window->toolbar.toolbar, &trect);
   1006         icvScreenToClient(window->frame, &trect);
   1007         SubtractRect( &rect, &crect, &trect);
   1008     }
   1009     else
   1010         rect = crect;
   1011 
   1012     rect.top += gutter;
   1013     rect.left += gutter;
   1014     rect.bottom -= gutter;
   1015     rect.right -= gutter;
   1016 
   1017     return rect;
   1018 }
   1019 
   1020 // returns TRUE if there is a problem such as ERROR_IO_PENDING.
   1021 static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
   1022 {
   1023     BITMAP bmp;
   1024     GdiFlush();
   1025     HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
   1026     if( size )
   1027         size->cx = size->cy = 0;
   1028     if( data )
   1029         *data = 0;
   1030 
   1031     if (h == NULL)
   1032         return true;
   1033     if (GetObject(h, sizeof(bmp), &bmp) == 0)
   1034         return true;
   1035 
   1036     if( size )
   1037     {
   1038         size->cx = abs(bmp.bmWidth);
   1039         size->cy = abs(bmp.bmHeight);
   1040     }
   1041 
   1042     if( channels )
   1043         *channels = bmp.bmBitsPixel/8;
   1044 
   1045     if( data )
   1046         *data = bmp.bmBits;
   1047 
   1048     return false;
   1049 }
   1050 
   1051 
   1052 static void icvUpdateWindowPos( CvWindow* window )
   1053 {
   1054     RECT rect;
   1055     assert(window);
   1056 
   1057     if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
   1058     {
   1059         int i;
   1060         SIZE size = {0,0};
   1061         icvGetBitmapData( window, &size, 0, 0 );
   1062 
   1063         // Repeat two times because after the first resizing of the mainhWnd window
   1064         // toolbar may resize too
   1065         for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
   1066         {
   1067             RECT rmw, rw = icvCalcWindowRect(window );
   1068             MoveWindow(window->hwnd, rw.left, rw.top,
   1069                 rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
   1070             GetClientRect(window->hwnd, &rw);
   1071             GetWindowRect(window->frame, &rmw);
   1072             // Resize the mainhWnd window in order to make the bitmap fit into the child window
   1073             MoveWindow(window->frame, rmw.left, rmw.top,
   1074                 rmw.right - rmw.left + size.cx - rw.right + rw.left,
   1075                 rmw.bottom  - rmw.top + size.cy - rw.bottom + rw.top, TRUE );
   1076         }
   1077     }
   1078 
   1079     rect = icvCalcWindowRect(window);
   1080     MoveWindow(window->hwnd, rect.left, rect.top,
   1081                rect.right - rect.left + 1,
   1082                rect.bottom - rect.top + 1, TRUE );
   1083 }
   1084 
   1085 CV_IMPL void
   1086 cvShowImage( const char* name, const CvArr* arr )
   1087 {
   1088     CV_FUNCNAME( "cvShowImage" );
   1089 
   1090     __BEGIN__;
   1091 
   1092     CvWindow* window;
   1093     SIZE size = { 0, 0 };
   1094     int channels = 0;
   1095     void* dst_ptr = 0;
   1096     const int channels0 = 3;
   1097     int origin = 0;
   1098     CvMat stub, dst, *image;
   1099     bool changed_size = false; // philipg
   1100 
   1101     if( !name )
   1102         CV_ERROR( CV_StsNullPtr, "NULL name" );
   1103 
   1104     window = icvFindWindowByName(name);
   1105     if(!window)
   1106     {
   1107         cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
   1108         window = icvFindWindowByName(name);
   1109     }
   1110 
   1111     if( !window || !arr )
   1112         EXIT; // keep silence here.
   1113 
   1114     if( CV_IS_IMAGE_HDR( arr ))
   1115         origin = ((IplImage*)arr)->origin;
   1116 
   1117     CV_CALL( image = cvGetMat( arr, &stub ));
   1118 
   1119 #ifdef HAVE_OPENGL
   1120     if (window->useGl)
   1121     {
   1122         cv::imshow(name, cv::cvarrToMat(image));
   1123         return;
   1124     }
   1125 #endif
   1126 
   1127     if (window->image)
   1128         // if there is something wrong with these system calls, we cannot display image...
   1129         if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
   1130             return;
   1131 
   1132     if( size.cx != image->width || size.cy != image->height || channels != channels0 )
   1133     {
   1134         changed_size = true;
   1135 
   1136         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
   1137         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
   1138 
   1139         DeleteObject( SelectObject( window->dc, window->image ));
   1140         window->image = 0;
   1141 
   1142         size.cx = image->width;
   1143         size.cy = image->height;
   1144         channels = channels0;
   1145 
   1146         FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
   1147 
   1148         window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
   1149                                       DIB_RGB_COLORS, &dst_ptr, 0, 0));
   1150     }
   1151 
   1152     cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3,
   1153                      dst_ptr, (size.cx * channels + 3) & -4 );
   1154     cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
   1155 
   1156     // ony resize window if needed
   1157     if (changed_size)
   1158         icvUpdateWindowPos(window);
   1159     InvalidateRect(window->hwnd, 0, 0);
   1160     // philipg: this is not needed and just slows things down
   1161     //    UpdateWindow(window->hwnd);
   1162 
   1163     __END__;
   1164 }
   1165 
   1166 #if 0
   1167 CV_IMPL void
   1168 cvShowImageHWND(HWND w_hWnd, const CvArr* arr)
   1169 {
   1170     CV_FUNCNAME( "cvShowImageHWND" );
   1171 
   1172     __BEGIN__;
   1173 
   1174     SIZE size = { 0, 0 };
   1175     int channels = 0;
   1176     void* dst_ptr = 0;
   1177     const int channels0 = 3;
   1178     int origin = 0;
   1179     CvMat stub, dst, *image;
   1180     bool changed_size = false;
   1181     BITMAPINFO tempbinfo;
   1182     HDC hdc = NULL;
   1183 
   1184     if( !arr )
   1185         EXIT;
   1186     if( !w_hWnd )
   1187         EXIT;
   1188 
   1189     hdc = GetDC(w_hWnd);
   1190 
   1191     if( CV_IS_IMAGE_HDR( arr ) )
   1192         origin = ((IplImage*)arr)->origin;
   1193 
   1194     CV_CALL( image = cvGetMat( arr, &stub ) );
   1195 
   1196     if ( hdc )
   1197     {
   1198             //GetBitmapData
   1199             BITMAP bmp;
   1200             GdiFlush();
   1201             HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );
   1202 
   1203             if (h == NULL)
   1204             EXIT;
   1205             if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
   1206             EXIT;
   1207 
   1208             channels = bmp.bmBitsPixel/8;
   1209             dst_ptr = bmp.bmBits;
   1210      }
   1211 
   1212     if( size.cx != image->width || size.cy != image->height || channels != channels0 )
   1213     {
   1214         changed_size = true;
   1215 
   1216         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
   1217         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
   1218 
   1219         BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
   1220                 CV_Assert( FALSE != bDeleteObj );
   1221 
   1222         size.cx = image->width;
   1223         size.cy = image->height;
   1224         channels = channels0;
   1225 
   1226         FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
   1227 
   1228         SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
   1229     }
   1230 
   1231     cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
   1232     cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );
   1233 
   1234     // Image stretching to fit the window
   1235     RECT rect;
   1236     GetClientRect(w_hWnd, &rect);
   1237     StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, &tempbinfo, DIB_RGB_COLORS, SRCCOPY );
   1238 
   1239     // ony resize window if needed
   1240     InvalidateRect(w_hWnd, 0, 0);
   1241 
   1242     __END__;
   1243 }
   1244 #endif
   1245 
   1246 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
   1247 {
   1248     CV_FUNCNAME( "cvResizeWindow" );
   1249 
   1250     __BEGIN__;
   1251 
   1252     int i;
   1253     CvWindow* window;
   1254     RECT rmw, rw, rect;
   1255 
   1256     if( !name )
   1257         CV_ERROR( CV_StsNullPtr, "NULL name" );
   1258 
   1259     window = icvFindWindowByName(name);
   1260     if(!window)
   1261         EXIT;
   1262 
   1263     // Repeat two times because after the first resizing of the mainhWnd window
   1264     // toolbar may resize too
   1265     for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
   1266     {
   1267         rw = icvCalcWindowRect(window);
   1268         MoveWindow(window->hwnd, rw.left, rw.top,
   1269             rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE);
   1270         GetClientRect(window->hwnd, &rw);
   1271         GetWindowRect(window->frame, &rmw);
   1272         // Resize the mainhWnd window in order to make the bitmap fit into the child window
   1273         MoveWindow(window->frame, rmw.left, rmw.top,
   1274             rmw.right - rmw.left + width - rw.right + rw.left,
   1275             rmw.bottom  - rmw.top + height - rw.bottom + rw.top, TRUE);
   1276     }
   1277 
   1278     rect = icvCalcWindowRect(window);
   1279     MoveWindow(window->hwnd, rect.left, rect.top,
   1280         rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE);
   1281 
   1282     __END__;
   1283 }
   1284 
   1285 
   1286 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
   1287 {
   1288     CV_FUNCNAME( "cvMoveWindow" );
   1289 
   1290     __BEGIN__;
   1291 
   1292     CvWindow* window;
   1293     RECT rect;
   1294 
   1295     if( !name )
   1296         CV_ERROR( CV_StsNullPtr, "NULL name" );
   1297 
   1298     window = icvFindWindowByName(name);
   1299     if(!window)
   1300         EXIT;
   1301 
   1302     GetWindowRect( window->frame, &rect );
   1303     MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
   1304 
   1305     __END__;
   1306 }
   1307 
   1308 
   1309 static LRESULT CALLBACK
   1310 MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
   1311 {
   1312     CvWindow* window = icvWindowByHWND( hwnd );
   1313     if( !window )
   1314         return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1315 
   1316     switch(uMsg)
   1317     {
   1318     case WM_COPY:
   1319         ::SendMessage(window->hwnd, uMsg, wParam, lParam);
   1320         break;
   1321 
   1322     case WM_DESTROY:
   1323 
   1324         icvRemoveWindow(window);
   1325         // Do nothing!!!
   1326         //PostQuitMessage(0);
   1327         break;
   1328 
   1329     case WM_GETMINMAXINFO:
   1330         if( !(window->flags & CV_WINDOW_AUTOSIZE) )
   1331         {
   1332             MINMAXINFO* minmax = (MINMAXINFO*)lParam;
   1333             RECT rect;
   1334             LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam);
   1335 
   1336             minmax->ptMinTrackSize.y = 100;
   1337             minmax->ptMinTrackSize.x = 100;
   1338 
   1339             if( window->toolbar.first )
   1340             {
   1341                 GetWindowRect( window->toolbar.first->hwnd, &rect );
   1342                 minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
   1343                 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
   1344             }
   1345             return retval;
   1346         }
   1347         break;
   1348 
   1349     case WM_WINDOWPOSCHANGED:
   1350         {
   1351             WINDOWPOS* pos = (WINDOWPOS*)lParam;
   1352 
   1353             // Update the toolbar pos/size
   1354             if(window->toolbar.toolbar)
   1355             {
   1356                 RECT rect;
   1357                 GetWindowRect(window->toolbar.toolbar, &rect);
   1358                 MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
   1359             }
   1360 
   1361             if(!(window->flags & CV_WINDOW_AUTOSIZE))
   1362                 icvUpdateWindowPos(window);
   1363 
   1364             break;
   1365         }
   1366 
   1367     case WM_WINDOWPOSCHANGING:
   1368        {
   1369           // Snap window to screen edges with multi-monitor support. // Adi Shavit
   1370           LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
   1371 
   1372           RECT rect;
   1373           GetWindowRect(window->frame, &rect);
   1374 
   1375           HMONITOR hMonitor;
   1376           hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
   1377 
   1378           MONITORINFO mi;
   1379           mi.cbSize = sizeof(mi);
   1380           GetMonitorInfo(hMonitor, &mi);
   1381 
   1382           const int SNAP_DISTANCE = 15;
   1383 
   1384           if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
   1385              pos->x = mi.rcMonitor.left;               // snap to left edge
   1386           else
   1387              if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
   1388                 pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge
   1389 
   1390           if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
   1391              pos->y = mi.rcMonitor.top;                 // snap to top edge
   1392           else
   1393              if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
   1394                 pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
   1395        }
   1396 
   1397     case WM_ACTIVATE:
   1398         if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
   1399             SetFocus(window->hwnd);
   1400         break;
   1401 
   1402     case WM_MOUSEWHEEL:
   1403     case WM_MOUSEHWHEEL:
   1404        if( window->on_mouse )
   1405        {
   1406           int flags = (wParam & MK_LBUTTON      ? CV_EVENT_FLAG_LBUTTON  : 0)|
   1407                       (wParam & MK_RBUTTON      ? CV_EVENT_FLAG_RBUTTON  : 0)|
   1408                       (wParam & MK_MBUTTON      ? CV_EVENT_FLAG_MBUTTON  : 0)|
   1409                       (wParam & MK_CONTROL      ? CV_EVENT_FLAG_CTRLKEY  : 0)|
   1410                       (wParam & MK_SHIFT        ? CV_EVENT_FLAG_SHIFTKEY : 0)|
   1411                       (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY   : 0);
   1412           int event = (uMsg == WM_MOUSEWHEEL    ? CV_EVENT_MOUSEWHEEL    : CV_EVENT_MOUSEHWHEEL);
   1413 
   1414           // Set the wheel delta of mouse wheel to be in the upper word of 'event'
   1415           int delta = GET_WHEEL_DELTA_WPARAM(wParam);
   1416           flags |= (delta << 16);
   1417 
   1418           POINT pt;
   1419           pt.x = GET_X_LPARAM( lParam );
   1420           pt.y = GET_Y_LPARAM( lParam );
   1421           ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.
   1422 
   1423           RECT rect;
   1424           GetClientRect( window->hwnd, &rect );
   1425 
   1426           SIZE size = {0,0};
   1427           icvGetBitmapData( window, &size, 0, 0 );
   1428 
   1429           window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
   1430                                    pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
   1431                                    window->on_mouse_param );
   1432        }
   1433        break;
   1434 
   1435     case WM_ERASEBKGND:
   1436         {
   1437             RECT cr, tr, wrc;
   1438             HRGN rgn, rgn1, rgn2;
   1439             int ret;
   1440             HDC hdc = (HDC)wParam;
   1441             GetWindowRect(window->hwnd, &cr);
   1442             icvScreenToClient(window->frame, &cr);
   1443             if(window->toolbar.toolbar)
   1444             {
   1445                 GetWindowRect(window->toolbar.toolbar, &tr);
   1446                 icvScreenToClient(window->frame, &tr);
   1447             }
   1448             else
   1449                 tr.left = tr.top = tr.right = tr.bottom = 0;
   1450 
   1451             GetClientRect(window->frame, &wrc);
   1452 
   1453             rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
   1454             rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
   1455             rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom);
   1456             ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
   1457             ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
   1458 
   1459             if(ret != NULLREGION && ret != ERROR)
   1460                 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
   1461 
   1462             DeleteObject(rgn);
   1463             DeleteObject(rgn1);
   1464             DeleteObject(rgn2);
   1465         }
   1466         return 1;
   1467     }
   1468 
   1469     return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1470 }
   1471 
   1472 
   1473 static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
   1474 {
   1475     CvWindow* window = icvWindowByHWND(hwnd);
   1476     if( !window )
   1477         // This window is not mentioned in HighGUI storage
   1478         // Actually, this should be error except for the case of calls to CreateWindow
   1479         return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1480 
   1481     // Process the message
   1482     switch(uMsg)
   1483     {
   1484     case WM_COPY:
   1485         {
   1486             if (!::OpenClipboard(hwnd) )
   1487                 break;
   1488 
   1489             HDC hDC       = 0;
   1490             HDC memDC     = 0;
   1491             HBITMAP memBM = 0;
   1492 
   1493             // We'll use a do-while(0){} scope as a single-run breakable scope
   1494             // Upon any error we can jump out of the single-time while scope to clean up the resources.
   1495             do
   1496             {
   1497                 if (!::EmptyClipboard())
   1498                     break;
   1499 
   1500                 if(!window->image)
   1501                     break;
   1502 
   1503                 // Get window device context
   1504                 if (0 == (hDC = ::GetDC(hwnd)))
   1505                     break;
   1506 
   1507                 // Create another DC compatible with hDC
   1508                 if (0 == (memDC = ::CreateCompatibleDC( hDC )))
   1509                     break;
   1510 
   1511                 // Determine the bitmap's dimensions
   1512                 int nchannels = 3;
   1513                 SIZE size = {0,0};
   1514                 icvGetBitmapData( window, &size, &nchannels, 0 );
   1515 
   1516                 // Create bitmap to draw on and it in the new DC
   1517                 if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
   1518                     break;
   1519 
   1520                 if (!::SelectObject( memDC, memBM ))
   1521                     break;
   1522 
   1523                 // Begin drawing to DC
   1524                 if (!::SetStretchBltMode(memDC, COLORONCOLOR))
   1525                     break;
   1526 
   1527                 RGBQUAD table[256];
   1528                 if( 1 == nchannels )
   1529                 {
   1530                     for(int i = 0; i < 256; ++i)
   1531                     {
   1532                         table[i].rgbBlue = (unsigned char)i;
   1533                         table[i].rgbGreen = (unsigned char)i;
   1534                         table[i].rgbRed = (unsigned char)i;
   1535                     }
   1536                     if (!::SetDIBColorTable(window->dc, 0, 255, table))
   1537                         break;
   1538                 }
   1539 
   1540                 // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.
   1541 
   1542                 // Render the image to the dc/bitmap (at original size).
   1543                 if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ))
   1544                     break;
   1545 
   1546                 // Finally, set bitmap to clipboard
   1547                 ::SetClipboardData(CF_BITMAP, memBM);
   1548             } while (0,0); // (0,0) instead of (0) to avoid MSVC compiler warning C4127: "conditional expression is constant"
   1549 
   1550             //////////////////////////////////////////////////////////////////////////
   1551             // if handle is allocated (i.e. != 0) then clean-up.
   1552             if (memBM) ::DeleteObject(memBM);
   1553             if (memDC) ::DeleteDC(memDC);
   1554             if (hDC)   ::ReleaseDC(hwnd, hDC);
   1555             ::CloseClipboard();
   1556             break;
   1557         }
   1558 
   1559     case WM_WINDOWPOSCHANGING:
   1560         {
   1561             LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
   1562             RECT rect = icvCalcWindowRect(window);
   1563             pos->x = rect.left;
   1564             pos->y = rect.top;
   1565             pos->cx = rect.right - rect.left + 1;
   1566             pos->cy = rect.bottom - rect.top + 1;
   1567         }
   1568         break;
   1569 
   1570     case WM_LBUTTONDOWN:
   1571     case WM_RBUTTONDOWN:
   1572     case WM_MBUTTONDOWN:
   1573     case WM_LBUTTONDBLCLK:
   1574     case WM_RBUTTONDBLCLK:
   1575     case WM_MBUTTONDBLCLK:
   1576     case WM_LBUTTONUP:
   1577     case WM_RBUTTONUP:
   1578     case WM_MBUTTONUP:
   1579     case WM_MOUSEMOVE:
   1580         if( window->on_mouse )
   1581         {
   1582             POINT pt;
   1583 
   1584             int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)|
   1585                         (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)|
   1586                         (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)|
   1587                         (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)|
   1588                         (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)|
   1589                         (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0);
   1590             int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN :
   1591                         uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN :
   1592                         uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN :
   1593                         uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP :
   1594                         uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP :
   1595                         uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP :
   1596                         uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK :
   1597                         uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
   1598                         uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
   1599                                                    CV_EVENT_MOUSEMOVE;
   1600             if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
   1601                 SetCapture( hwnd );
   1602             if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
   1603                 ReleaseCapture();
   1604 
   1605             pt.x = GET_X_LPARAM( lParam );
   1606             pt.y = GET_Y_LPARAM( lParam );
   1607 
   1608             if (window->flags & CV_WINDOW_AUTOSIZE)
   1609             {
   1610                 // As user can't change window size, do not scale window coordinates. Underlying windowing system
   1611                 // may prevent full window from being displayed and in this case coordinates should not be scaled.
   1612                 window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param );
   1613             } else {
   1614                 // Full window is displayed using different size. Scale coordinates to match underlying positions.
   1615                 RECT rect;
   1616                 SIZE size = {0, 0};
   1617 
   1618                 GetClientRect( window->hwnd, &rect );
   1619                 icvGetBitmapData( window, &size, 0, 0 );
   1620 
   1621                 window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
   1622                                          pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
   1623                                          window->on_mouse_param );
   1624             }
   1625         }
   1626         break;
   1627 
   1628     case WM_PAINT:
   1629         if(window->image != 0)
   1630         {
   1631             int nchannels = 3;
   1632             SIZE size = {0,0};
   1633             PAINTSTRUCT paint;
   1634             HDC hdc;
   1635             RGBQUAD table[256];
   1636 
   1637             // Determine the bitmap's dimensions
   1638             icvGetBitmapData( window, &size, &nchannels, 0 );
   1639 
   1640             hdc = BeginPaint(hwnd, &paint);
   1641             SetStretchBltMode(hdc, COLORONCOLOR);
   1642 
   1643             if( nchannels == 1 )
   1644             {
   1645                 int i;
   1646                 for(i = 0; i < 256; i++)
   1647                 {
   1648                     table[i].rgbBlue = (unsigned char)i;
   1649                     table[i].rgbGreen = (unsigned char)i;
   1650                     table[i].rgbRed = (unsigned char)i;
   1651                 }
   1652                 SetDIBColorTable(window->dc, 0, 255, table);
   1653             }
   1654 
   1655             if(window->flags & CV_WINDOW_AUTOSIZE)
   1656             {
   1657                 BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
   1658             }
   1659             else
   1660             {
   1661                 RECT rect;
   1662                 GetClientRect(window->hwnd, &rect);
   1663                 StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
   1664                             window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
   1665             }
   1666             //DeleteDC(hdc);
   1667             EndPaint(hwnd, &paint);
   1668         }
   1669 #ifdef HAVE_OPENGL
   1670         else if(window->useGl)
   1671         {
   1672             drawGl(window);
   1673             return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1674         }
   1675 #endif
   1676         else
   1677         {
   1678             return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1679         }
   1680         return 0;
   1681 
   1682     case WM_ERASEBKGND:
   1683         if(window->image)
   1684             return 0;
   1685         break;
   1686 
   1687     case WM_DESTROY:
   1688 
   1689         icvRemoveWindow(window);
   1690         // Do nothing!!!
   1691         //PostQuitMessage(0);
   1692         break;
   1693 
   1694     case WM_SETCURSOR:
   1695         SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR));
   1696         return 0;
   1697 
   1698     case WM_KEYDOWN:
   1699         window->last_key = (int)wParam;
   1700         return 0;
   1701 
   1702     case WM_SIZE:
   1703         window->width = LOWORD(lParam);
   1704         window->height = HIWORD(lParam);
   1705 
   1706 #ifdef HAVE_OPENGL
   1707         if (window->useGl)
   1708             resizeGl(window);
   1709 #endif
   1710     }
   1711 
   1712     return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1713 }
   1714 
   1715 
   1716 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
   1717 {
   1718     LRESULT ret;
   1719 
   1720     if( hg_on_preprocess )
   1721     {
   1722         int was_processed = 0;
   1723         int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
   1724         if( was_processed )
   1725             return rethg;
   1726     }
   1727     ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
   1728 
   1729     if(hg_on_postprocess)
   1730     {
   1731         int was_processed = 0;
   1732         int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
   1733         if( was_processed )
   1734             return rethg;
   1735     }
   1736 
   1737     return ret;
   1738 }
   1739 
   1740 
   1741 static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
   1742 {
   1743     const int max_name_len = 10;
   1744     const char* suffix = "";
   1745     char pos_text[32];
   1746     int name_len;
   1747 
   1748     if( trackbar->data )
   1749         *trackbar->data = pos;
   1750 
   1751     if( trackbar->pos != pos )
   1752     {
   1753         trackbar->pos = pos;
   1754         if( trackbar->notify2 )
   1755             trackbar->notify2(pos, trackbar->userdata);
   1756         if( trackbar->notify )
   1757             trackbar->notify(pos);
   1758 
   1759         name_len = (int)strlen(trackbar->name);
   1760 
   1761         if( name_len > max_name_len )
   1762         {
   1763             int start_len = max_name_len*2/3;
   1764             int end_len = max_name_len - start_len - 2;
   1765             memcpy( pos_text, trackbar->name, start_len );
   1766             memcpy( pos_text + start_len, "...", 3 );
   1767             memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
   1768         }
   1769         else
   1770         {
   1771             memcpy( pos_text, trackbar->name, name_len + 1);
   1772         }
   1773 
   1774         sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
   1775         SetWindowText( trackbar->buddy, pos_text );
   1776     }
   1777 }
   1778 
   1779 
   1780 static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
   1781 {
   1782     CvWindow* window = icvWindowByHWND( hwnd );
   1783     if(!window)
   1784         return DefWindowProc(hwnd, uMsg, wParam, lParam);
   1785 
   1786     // Control messages processing
   1787     switch(uMsg)
   1788     {
   1789     // Slider processing
   1790     case WM_HSCROLL:
   1791         {
   1792             HWND slider = (HWND)lParam;
   1793             int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
   1794             CvTrackbar* trackbar = icvTrackbarByHWND( slider );
   1795 
   1796             if( trackbar )
   1797             {
   1798                 if( trackbar->pos != pos )
   1799                     icvUpdateTrackbar( trackbar, pos );
   1800             }
   1801 
   1802             SetFocus( window->hwnd );
   1803             return 0;
   1804         }
   1805 
   1806     case WM_NCCALCSIZE:
   1807         {
   1808             LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
   1809             int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
   1810 
   1811             if(window->toolbar.rows != rows)
   1812             {
   1813                 SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
   1814                 CvTrackbar* trackbar = window->toolbar.first;
   1815 
   1816                 for( ; trackbar != 0; trackbar = trackbar->next )
   1817                 {
   1818                     RECT rect;
   1819                     SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
   1820                                (WPARAM)trackbar->id, (LPARAM)&rect);
   1821                     MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
   1822                                rect.right - rect.left - HG_BUDDY_WIDTH,
   1823                                rect.bottom - rect.top, FALSE);
   1824                     MoveWindow(trackbar->buddy, rect.left, rect.top,
   1825                                HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
   1826                 }
   1827                 window->toolbar.rows = rows;
   1828             }
   1829             return ret;
   1830         }
   1831     }
   1832 
   1833     return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
   1834 }
   1835 
   1836 
   1837 CV_IMPL void
   1838 cvDestroyAllWindows(void)
   1839 {
   1840     CvWindow* window = hg_windows;
   1841 
   1842     while( window )
   1843     {
   1844         HWND mainhWnd = window->frame;
   1845         HWND hwnd = window->hwnd;
   1846         window = window->next;
   1847 
   1848         SendMessage( hwnd, WM_CLOSE, 0, 0 );
   1849         SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
   1850     }
   1851 }
   1852 
   1853 static void showSaveDialog(CvWindow* window)
   1854 {
   1855     if (!window || !window->image)
   1856         return;
   1857 
   1858     SIZE sz;
   1859     int channels;
   1860     void* data;
   1861     if (icvGetBitmapData(window, &sz, &channels, &data))
   1862         return; // nothing to save
   1863 
   1864     char szFileName[MAX_PATH] = "";
   1865     // try to use window title as file name
   1866     GetWindowText(window->frame, szFileName, MAX_PATH);
   1867 
   1868     OPENFILENAME ofn;
   1869     ZeroMemory(&ofn, sizeof(ofn));
   1870 #ifdef OPENFILENAME_SIZE_VERSION_400
   1871     // we are not going to use new fields any way
   1872     ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
   1873 #else
   1874     ofn.lStructSize = sizeof(ofn);
   1875 #endif
   1876     ofn.hwndOwner = window->hwnd;
   1877     ofn.lpstrFilter = "Portable Network Graphics files (*.png)\0*.png\0"
   1878                       "JPEG files (*.jpeg;*.jpg;*.jpe)\0*.jpeg;*.jpg;*.jpe\0"
   1879                       "Windows bitmap (*.bmp;*.dib)\0*.bmp;*.dib\0"
   1880                       "TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
   1881                       "JPEG-2000 files (*.jp2)\0*.jp2\0"
   1882                       "WebP files (*.webp)\0*.webp\0"
   1883                       "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)\0*.pbm;*.pgm;*.ppm;*.pxm;*.pnm\0"
   1884                       "OpenEXR Image files (*.exr)\0*.exr\0"
   1885                       "Radiance HDR (*.hdr;*.pic)\0*.hdr;*.pic\0"
   1886                       "Sun raster files (*.sr;*.ras)\0*.sr;*.ras\0"
   1887                       "All Files (*.*)\0*.*\0";
   1888     ofn.lpstrFile = szFileName;
   1889     ofn.nMaxFile = MAX_PATH;
   1890     ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_NOCHANGEDIR;
   1891     ofn.lpstrDefExt = "png";
   1892 
   1893     if (GetSaveFileName(&ofn))
   1894     {
   1895         cv::Mat tmp; cv::flip(cv::Mat(sz.cy, sz.cx, CV_8UC(channels), data), tmp, 0);
   1896         cv::imwrite(szFileName, tmp);
   1897     }
   1898 }
   1899 
   1900 CV_IMPL int
   1901 cvWaitKey( int delay )
   1902 {
   1903     int time0 = GetTickCount();
   1904 
   1905     for(;;)
   1906     {
   1907         CvWindow* window;
   1908         MSG message;
   1909         int is_processed = 0;
   1910 
   1911         if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
   1912             return -1;
   1913 
   1914         if( delay <= 0 )
   1915             GetMessage(&message, 0, 0, 0);
   1916         else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
   1917         {
   1918             Sleep(1);
   1919             continue;
   1920         }
   1921 
   1922         for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
   1923         {
   1924             if( window->hwnd == message.hwnd || window->frame == message.hwnd )
   1925             {
   1926                 is_processed = 1;
   1927                 switch(message.message)
   1928                 {
   1929                 case WM_DESTROY:
   1930                 case WM_CHAR:
   1931                     DispatchMessage(&message);
   1932                     return (int)message.wParam;
   1933 
   1934                 case WM_SYSKEYDOWN:
   1935                     if( message.wParam == VK_F10 )
   1936                     {
   1937                         is_processed = 1;
   1938                         return (int)(message.wParam << 16);
   1939                     }
   1940                     break;
   1941 
   1942                 case WM_KEYDOWN:
   1943                     TranslateMessage(&message);
   1944                     if( (message.wParam >= VK_F1 && message.wParam <= VK_F24)       ||
   1945                         message.wParam == VK_HOME   || message.wParam == VK_END     ||
   1946                         message.wParam == VK_UP     || message.wParam == VK_DOWN    ||
   1947                         message.wParam == VK_LEFT   || message.wParam == VK_RIGHT   ||
   1948                         message.wParam == VK_INSERT || message.wParam == VK_DELETE  ||
   1949                         message.wParam == VK_PRIOR  || message.wParam == VK_NEXT )
   1950                     {
   1951                         DispatchMessage(&message);
   1952                         is_processed = 1;
   1953                         return (int)(message.wParam << 16);
   1954                     }
   1955 
   1956                     // Intercept Ctrl+C for copy to clipboard
   1957                     if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
   1958                         ::SendMessage(message.hwnd, WM_COPY, 0, 0);
   1959 
   1960                     // Intercept Ctrl+S for "save as" dialog
   1961                     if ('S' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
   1962                         showSaveDialog(window);
   1963 
   1964                 default:
   1965                     DispatchMessage(&message);
   1966                     is_processed = 1;
   1967                     break;
   1968                 }
   1969             }
   1970         }
   1971 
   1972         if( !is_processed )
   1973         {
   1974             TranslateMessage(&message);
   1975             DispatchMessage(&message);
   1976         }
   1977     }
   1978 }
   1979 
   1980 
   1981 static CvTrackbar*
   1982 icvFindTrackbarByName( const CvWindow* window, const char* name )
   1983 {
   1984     CvTrackbar* trackbar = window->toolbar.first;
   1985 
   1986     for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
   1987         ;
   1988 
   1989     return trackbar;
   1990 }
   1991 
   1992 
   1993 static int
   1994 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
   1995                    int* val, int count, CvTrackbarCallback on_notify,
   1996                    CvTrackbarCallback2 on_notify2, void* userdata )
   1997 {
   1998     int result = 0;
   1999 
   2000     CV_FUNCNAME( "icvCreateTrackbar" );
   2001 
   2002     __BEGIN__;
   2003 
   2004     char slider_name[32];
   2005     CvWindow* window = 0;
   2006     CvTrackbar* trackbar = 0;
   2007     int pos = 0;
   2008 
   2009     if( !window_name || !trackbar_name )
   2010         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
   2011 
   2012     if( count < 0 )
   2013         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
   2014 
   2015     window = icvFindWindowByName(window_name);
   2016     if( !window )
   2017         EXIT;
   2018 
   2019     trackbar = icvFindTrackbarByName(window,trackbar_name);
   2020     if( !trackbar )
   2021     {
   2022         TBBUTTON tbs = {0};
   2023         TBBUTTONINFO tbis = {0};
   2024         RECT rect;
   2025         int bcount;
   2026         int len = (int)strlen( trackbar_name );
   2027 
   2028         // create toolbar if it is not created yet
   2029         if( !window->toolbar.toolbar )
   2030         {
   2031             const int default_height = 30;
   2032 
   2033             // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
   2034             window->toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
   2035                                         WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
   2036                                         0, 0, 0, 0,
   2037                                         window->frame, NULL, GetModuleHandle(NULL), NULL);
   2038             // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
   2039             SendMessage(window->toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
   2040 
   2041             GetClientRect(window->frame, &rect);
   2042             MoveWindow( window->toolbar.toolbar, 0, 0,
   2043                         rect.right - rect.left, default_height, TRUE);
   2044             SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
   2045             ShowWindow(window->toolbar.toolbar, SW_SHOW);
   2046 
   2047             window->toolbar.first = 0;
   2048             window->toolbar.pos = 0;
   2049             window->toolbar.rows = 0;
   2050             window->toolbar.toolBarProc =
   2051                 (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
   2052 
   2053             icvUpdateWindowPos(window);
   2054 
   2055             // Subclassing from toolbar
   2056             icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
   2057             icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
   2058         }
   2059 
   2060         /* Retrieve current buttons count */
   2061         bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
   2062 
   2063         if(bcount > 1)
   2064         {
   2065             /* If this is not the first button then we need to
   2066             separate it from the previous one */
   2067             tbs.iBitmap = 0;
   2068             tbs.idCommand = bcount; // Set button id to it's number
   2069             tbs.iString = 0;
   2070             tbs.fsStyle = TBSTYLE_SEP;
   2071             tbs.fsState = TBSTATE_ENABLED;
   2072             SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
   2073 
   2074             // Retrieve current buttons count
   2075             bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
   2076         }
   2077 
   2078         /* Add a button which we're going to cover with the slider */
   2079         tbs.iBitmap = 0;
   2080         tbs.idCommand = bcount; // Set button id to it's number
   2081         tbs.fsState = TBSTATE_ENABLED;
   2082 #if 0/*!defined WIN64 && !defined EM64T*/
   2083         tbs.fsStyle = 0;
   2084         tbs.iString = 0;
   2085 #else
   2086 
   2087 #ifndef TBSTYLE_AUTOSIZE
   2088 #define TBSTYLE_AUTOSIZE        0x0010
   2089 #endif
   2090 
   2091 #ifndef TBSTYLE_GROUP
   2092 #define TBSTYLE_GROUP           0x0004
   2093 #endif
   2094         //tbs.fsStyle = TBSTYLE_AUTOSIZE;
   2095         tbs.fsStyle = TBSTYLE_GROUP;
   2096         tbs.iString = (INT_PTR)trackbar_text;
   2097 #endif
   2098         SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
   2099 
   2100         /* Adjust button size to the slider */
   2101         tbis.cbSize = sizeof(tbis);
   2102         tbis.dwMask = TBIF_SIZE;
   2103 
   2104         GetClientRect(window->hwnd, &rect);
   2105         tbis.cx = (unsigned short)(rect.right - rect.left);
   2106 
   2107         SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
   2108             (WPARAM)tbs.idCommand, (LPARAM)&tbis);
   2109 
   2110         /* Get button pos */
   2111         SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
   2112             (WPARAM)tbs.idCommand, (LPARAM)&rect);
   2113 
   2114         /* Create a slider */
   2115         trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
   2116         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
   2117         trackbar->notify = 0;
   2118         trackbar->notify2 = 0;
   2119         trackbar->parent = window;
   2120         trackbar->pos = 0;
   2121         trackbar->data = 0;
   2122         trackbar->id = bcount;
   2123         trackbar->next = window->toolbar.first;
   2124         trackbar->name = (char*)(trackbar + 1);
   2125         memcpy( trackbar->name, trackbar_name, len + 1 );
   2126         window->toolbar.first = trackbar;
   2127 
   2128         sprintf(slider_name, "Trackbar%p", val);
   2129         trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
   2130                             WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
   2131                             TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
   2132                             rect.left + HG_BUDDY_WIDTH, rect.top,
   2133                             rect.right - rect.left - HG_BUDDY_WIDTH,
   2134                             rect.bottom - rect.top, window->toolbar.toolbar,
   2135                             (HMENU)(size_t)bcount, hg_hinstance, 0);
   2136 
   2137         sprintf(slider_name,"Buddy%p", val);
   2138         trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
   2139                             WS_CHILD | SS_RIGHT,
   2140                             rect.left, rect.top,
   2141                             HG_BUDDY_WIDTH, rect.bottom - rect.top,
   2142                             window->toolbar.toolbar, 0, hg_hinstance, 0);
   2143 
   2144         icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
   2145 
   2146         /* Minimize the number of rows */
   2147         SendMessage( window->toolbar.toolbar, TB_SETROWS,
   2148                      MAKEWPARAM(1, FALSE), (LPARAM)&rect );
   2149     }
   2150     else
   2151     {
   2152         trackbar->data = 0;
   2153         trackbar->notify = 0;
   2154         trackbar->notify2 = 0;
   2155     }
   2156 
   2157     trackbar->maxval = count;
   2158 
   2159     /* Adjust slider parameters */
   2160     SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
   2161     SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)count);
   2162     SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
   2163     if( val )
   2164         pos = *val;
   2165 
   2166     SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
   2167     SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
   2168 
   2169     trackbar->pos = -1;
   2170     icvUpdateTrackbar( trackbar, pos );
   2171     ShowWindow( trackbar->buddy, SW_SHOW );
   2172     ShowWindow( trackbar->hwnd, SW_SHOW );
   2173 
   2174     trackbar->notify = on_notify;
   2175     trackbar->notify2 = on_notify2;
   2176     trackbar->userdata = userdata;
   2177     trackbar->data = val;
   2178 
   2179     /* Resize the window to reflect the toolbar resizing*/
   2180     icvUpdateWindowPos(window);
   2181 
   2182     result = 1;
   2183 
   2184     __END__;
   2185 
   2186     return result;
   2187 }
   2188 
   2189 CV_IMPL int
   2190 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
   2191                   int* val, int count, CvTrackbarCallback on_notify )
   2192 {
   2193     return icvCreateTrackbar( trackbar_name, window_name, val, count,
   2194         on_notify, 0, 0 );
   2195 }
   2196 
   2197 CV_IMPL int
   2198 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
   2199                    int* val, int count, CvTrackbarCallback2 on_notify2,
   2200                    void* userdata )
   2201 {
   2202     return icvCreateTrackbar( trackbar_name, window_name, val, count,
   2203         0, on_notify2, userdata );
   2204 }
   2205 
   2206 CV_IMPL void
   2207 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
   2208 {
   2209     CV_FUNCNAME( "cvSetMouseCallback" );
   2210 
   2211     __BEGIN__;
   2212 
   2213     CvWindow* window = 0;
   2214 
   2215     if( !window_name )
   2216         CV_ERROR( CV_StsNullPtr, "NULL window name" );
   2217 
   2218     window = icvFindWindowByName(window_name);
   2219     if( !window )
   2220         EXIT;
   2221 
   2222     window->on_mouse = on_mouse;
   2223     window->on_mouse_param = param;
   2224 
   2225     __END__;
   2226 }
   2227 
   2228 
   2229 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
   2230 {
   2231     int pos = -1;
   2232 
   2233     CV_FUNCNAME( "cvGetTrackbarPos" );
   2234 
   2235     __BEGIN__;
   2236 
   2237     CvWindow* window;
   2238     CvTrackbar* trackbar = 0;
   2239 
   2240     if( trackbar_name == 0 || window_name == 0 )
   2241         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
   2242 
   2243     window = icvFindWindowByName( window_name );
   2244     if( window )
   2245         trackbar = icvFindTrackbarByName( window, trackbar_name );
   2246 
   2247     if( trackbar )
   2248         pos = trackbar->pos;
   2249 
   2250     __END__;
   2251 
   2252     return pos;
   2253 }
   2254 
   2255 
   2256 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
   2257 {
   2258     CV_FUNCNAME( "cvSetTrackbarPos" );
   2259 
   2260     __BEGIN__;
   2261 
   2262     CvWindow* window;
   2263     CvTrackbar* trackbar = 0;
   2264 
   2265     if( trackbar_name == 0 || window_name == 0 )
   2266         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
   2267 
   2268     window = icvFindWindowByName( window_name );
   2269     if( window )
   2270         trackbar = icvFindTrackbarByName( window, trackbar_name );
   2271 
   2272     if( trackbar )
   2273     {
   2274         if( pos < 0 )
   2275             pos = 0;
   2276 
   2277         if( pos > trackbar->maxval )
   2278             pos = trackbar->maxval;
   2279 
   2280         SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
   2281         icvUpdateTrackbar( trackbar, pos );
   2282     }
   2283 
   2284     __END__;
   2285 }
   2286 
   2287 
   2288 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
   2289 {
   2290     CV_FUNCNAME( "cvSetTrackbarMax" );
   2291 
   2292     __BEGIN__;
   2293 
   2294     if (maxval >= 0)
   2295     {
   2296         CvWindow* window = 0;
   2297         CvTrackbar* trackbar = 0;
   2298         if (trackbar_name == 0 || window_name == 0)
   2299         {
   2300             CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
   2301         }
   2302 
   2303         window = icvFindWindowByName(window_name);
   2304         if (window)
   2305         {
   2306             trackbar = icvFindTrackbarByName(window, trackbar_name);
   2307             if (trackbar)
   2308             {
   2309                 // The position will be min(pos, maxval).
   2310                 trackbar->maxval = maxval;
   2311                 SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
   2312             }
   2313         }
   2314     }
   2315 
   2316     __END__;
   2317 }
   2318 
   2319 
   2320 CV_IMPL void* cvGetWindowHandle( const char* window_name )
   2321 {
   2322     void* hwnd = 0;
   2323 
   2324     CV_FUNCNAME( "cvGetWindowHandle" );
   2325 
   2326     __BEGIN__;
   2327 
   2328     CvWindow* window;
   2329 
   2330     if( window_name == 0 )
   2331         CV_ERROR( CV_StsNullPtr, "NULL window name" );
   2332 
   2333     window = icvFindWindowByName( window_name );
   2334     if( window )
   2335         hwnd = (void*)window->hwnd;
   2336 
   2337     __END__;
   2338 
   2339     return hwnd;
   2340 }
   2341 
   2342 
   2343 CV_IMPL const char* cvGetWindowName( void* window_handle )
   2344 {
   2345     const char* window_name = "";
   2346 
   2347     CV_FUNCNAME( "cvGetWindowName" );
   2348 
   2349     __BEGIN__;
   2350 
   2351     CvWindow* window;
   2352 
   2353     if( window_handle == 0 )
   2354         CV_ERROR( CV_StsNullPtr, "NULL window" );
   2355 
   2356     window = icvWindowByHWND( (HWND)window_handle );
   2357     if( window )
   2358         window_name = window->name;
   2359 
   2360     __END__;
   2361 
   2362     return window_name;
   2363 }
   2364 
   2365 
   2366 CV_IMPL void
   2367 cvSetPreprocessFuncWin32_(const void* callback)
   2368 {
   2369     hg_on_preprocess = (CvWin32WindowCallback)callback;
   2370 }
   2371 
   2372 CV_IMPL void
   2373 cvSetPostprocessFuncWin32_(const void* callback)
   2374 {
   2375     hg_on_postprocess = (CvWin32WindowCallback)callback;
   2376 }
   2377 
   2378 #endif //WIN32
   2379