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