Add OpenCV source code
[platform/upstream/opencv.git] / modules / highgui / src / window_gtk.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 #ifndef WIN32
45
46 #ifdef HAVE_GTK
47
48 #include "gtk/gtk.h"
49 #include "gdk/gdkkeysyms.h"
50 #include <stdio.h>
51
52 #ifdef HAVE_OPENGL
53     #include <gtk/gtkgl.h>
54     #include <GL/gl.h>
55     #include <GL/glu.h>
56 #endif
57
58 // TODO Fix the initial window size when flags=0.  Right now the initial window is by default
59 // 320x240 size.  A better default would be actual size of the image.  Problem
60 // is determining desired window size with trackbars while still allowing resizing.
61 //
62 // Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio
63 // in totem/src/backend/bacon-video-widget-xine.c
64
65 ////////////////////////////////////////////////////////////
66 // CvImageWidget GTK Widget Public API
67 ////////////////////////////////////////////////////////////
68 typedef struct _CvImageWidget        CvImageWidget;
69 typedef struct _CvImageWidgetClass   CvImageWidgetClass;
70
71 struct _CvImageWidget {
72     GtkWidget widget;
73     CvMat * original_image;
74     CvMat * scaled_image;
75     int flags;
76 };
77
78 struct _CvImageWidgetClass
79 {
80   GtkWidgetClass parent_class;
81 };
82
83
84 /** Allocate new image viewer widget */
85 GtkWidget*     cvImageWidgetNew      (int flags);
86
87 /** Set the image to display in the widget */
88 void           cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr);
89
90 // standard GTK object macros
91 #define CV_IMAGE_WIDGET(obj)          GTK_CHECK_CAST (obj, cvImageWidget_get_type (), CvImageWidget)
92 #define CV_IMAGE_WIDGET_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass)
93 #define CV_IS_IMAGE_WIDGET(obj)       GTK_CHECK_TYPE (obj, cvImageWidget_get_type ())
94
95 /////////////////////////////////////////////////////////////////////////////
96 // Private API ////////////////////////////////////////////////////////
97 /////////////////////////////////////////////////////////////////////////////
98 GtkType        cvImageWidget_get_type (void);
99
100 static GtkWidgetClass * parent_class = NULL;
101
102 // flag to help size initial window
103 #define CV_WINDOW_NO_IMAGE 2
104
105 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){
106     CvMat * mat, stub;
107     int origin=0;
108
109     //printf("cvImageWidgetSetImage\n");
110
111     if( CV_IS_IMAGE_HDR( arr ))
112         origin = ((IplImage*)arr)->origin;
113
114     mat = cvGetMat(arr, &stub);
115
116     if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){
117         cvReleaseMat( &widget->original_image );
118     }
119     if(!widget->original_image){
120         widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 );
121         gtk_widget_queue_resize( GTK_WIDGET( widget ) );
122     }
123     cvConvertImage( mat, widget->original_image,
124                             (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
125     if(widget->scaled_image){
126         cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA );
127     }
128
129     // window does not refresh without this
130     gtk_widget_queue_draw( GTK_WIDGET(widget) );
131 }
132
133 GtkWidget*
134 cvImageWidgetNew (int flags)
135 {
136   CvImageWidget *image_widget;
137
138   image_widget = CV_IMAGE_WIDGET( gtk_type_new (cvImageWidget_get_type ()) );
139   image_widget->original_image = 0;
140   image_widget->scaled_image = 0;
141   image_widget->flags = flags | CV_WINDOW_NO_IMAGE;
142
143   return GTK_WIDGET (image_widget);
144 }
145
146 static void
147 cvImageWidget_realize (GtkWidget *widget)
148 {
149   GdkWindowAttr attributes;
150   gint attributes_mask;
151
152   //printf("cvImageWidget_realize\n");
153   g_return_if_fail (widget != NULL);
154   g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
155
156   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
157
158   attributes.x = widget->allocation.x;
159   attributes.y = widget->allocation.y;
160   attributes.width = widget->allocation.width;
161   attributes.height = widget->allocation.height;
162   attributes.wclass = GDK_INPUT_OUTPUT;
163   attributes.window_type = GDK_WINDOW_CHILD;
164   attributes.event_mask = gtk_widget_get_events (widget) |
165     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
166     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
167   attributes.visual = gtk_widget_get_visual (widget);
168   attributes.colormap = gtk_widget_get_colormap (widget);
169
170   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
171   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
172
173   widget->style = gtk_style_attach (widget->style, widget->window);
174
175   gdk_window_set_user_data (widget->window, widget);
176
177   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
178 }
179
180 static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){
181     float aspect = (float)im_width/(float)im_height;
182     float max_aspect = (float)max_width/(float)max_height;
183     if(aspect > max_aspect){
184         return cvSize( max_width, cvRound(max_width/aspect) );
185     }
186     return cvSize( cvRound(max_height*aspect), max_height );
187 }
188
189 static void
190 cvImageWidget_size_request (GtkWidget      *widget,
191                        GtkRequisition *requisition)
192 {
193     CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
194
195     //printf("cvImageWidget_size_request ");
196     // the case the first time cvShowImage called or when AUTOSIZE
197     if( image_widget->original_image &&
198         ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
199          (image_widget->flags & CV_WINDOW_NO_IMAGE)))
200     {
201         //printf("original ");
202         requisition->width = image_widget->original_image->cols;
203         requisition->height = image_widget->original_image->rows;
204     }
205     // default case
206     else if(image_widget->scaled_image){
207         //printf("scaled ");
208         requisition->width = image_widget->scaled_image->cols;
209         requisition->height = image_widget->scaled_image->rows;
210     }
211     // the case before cvShowImage called
212     else{
213         //printf("default ");
214         requisition->width = 320;
215         requisition->height = 240;
216     }
217     //printf("%d %d\n",requisition->width, requisition->height);
218 }
219
220 static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){
221     CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
222
223     //printf("cvImageWidget_set_size %d %d\n", max_width, max_height);
224
225     // don't allow to set the size
226     if(image_widget->flags & CV_WINDOW_AUTOSIZE) return;
227     if(!image_widget->original_image) return;
228
229     CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols,
230             image_widget->original_image->rows, max_width, max_height );
231
232     if( image_widget->scaled_image &&
233             ( image_widget->scaled_image->cols != scaled_image_size.width ||
234               image_widget->scaled_image->rows != scaled_image_size.height ))
235     {
236         cvReleaseMat( &image_widget->scaled_image );
237     }
238     if( !image_widget->scaled_image ){
239         image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width,        CV_8UC3 );
240
241
242     }
243     assert( image_widget->scaled_image );
244 }
245
246 static void
247 cvImageWidget_size_allocate (GtkWidget     *widget,
248                         GtkAllocation *allocation)
249 {
250   CvImageWidget *image_widget;
251
252   //printf("cvImageWidget_size_allocate\n");
253   g_return_if_fail (widget != NULL);
254   g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
255   g_return_if_fail (allocation != NULL);
256
257   widget->allocation = *allocation;
258   image_widget = CV_IMAGE_WIDGET (widget);
259
260
261   if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){
262       // (re) allocated scaled image
263       if( image_widget->flags & CV_WINDOW_NO_IMAGE ){
264           cvImageWidget_set_size( widget, image_widget->original_image->cols,
265                                           image_widget->original_image->rows);
266       }
267       else{
268           cvImageWidget_set_size( widget, allocation->width, allocation->height );
269       }
270       cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA );
271   }
272
273   if (GTK_WIDGET_REALIZED (widget))
274     {
275       image_widget = CV_IMAGE_WIDGET (widget);
276
277       if( image_widget->original_image &&
278               ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
279                (image_widget->flags & CV_WINDOW_NO_IMAGE)) )
280       {
281           widget->allocation.width = image_widget->original_image->cols;
282           widget->allocation.height = image_widget->original_image->rows;
283           gdk_window_move_resize( widget->window, allocation->x, allocation->y,
284                   image_widget->original_image->cols, image_widget->original_image->rows );
285           if(image_widget->flags & CV_WINDOW_NO_IMAGE){
286               image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
287               gtk_widget_queue_resize( GTK_WIDGET(widget) );
288           }
289       }
290       else{
291           gdk_window_move_resize (widget->window,
292                   allocation->x, allocation->y,
293                   allocation->width, allocation->height );
294
295       }
296     }
297 }
298
299 static void
300 cvImageWidget_destroy (GtkObject *object)
301 {
302   CvImageWidget *image_widget;
303
304   g_return_if_fail (object != NULL);
305   g_return_if_fail (CV_IS_IMAGE_WIDGET (object));
306
307   image_widget = CV_IMAGE_WIDGET (object);
308
309   cvReleaseMat( &image_widget->scaled_image );
310   cvReleaseMat( &image_widget->original_image );
311
312   if (GTK_OBJECT_CLASS (parent_class)->destroy)
313     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
314 }
315
316 static void cvImageWidget_class_init (CvImageWidgetClass * klass)
317 {
318   GtkObjectClass *object_class;
319   GtkWidgetClass *widget_class;
320
321   object_class = (GtkObjectClass*) klass;
322   widget_class = (GtkWidgetClass*) klass;
323
324   parent_class = GTK_WIDGET_CLASS( gtk_type_class (gtk_widget_get_type ()) );
325
326   object_class->destroy = cvImageWidget_destroy;
327
328   widget_class->realize = cvImageWidget_realize;
329   widget_class->size_request = cvImageWidget_size_request;
330   widget_class->size_allocate = cvImageWidget_size_allocate;
331   widget_class->button_press_event = NULL;
332   widget_class->button_release_event = NULL;
333   widget_class->motion_notify_event = NULL;
334 }
335
336 static void
337 cvImageWidget_init (CvImageWidget *image_widget)
338 {
339     image_widget->original_image=0;
340     image_widget->scaled_image=0;
341     image_widget->flags=0;
342 }
343
344 GtkType cvImageWidget_get_type (void){
345   static GtkType image_type = 0;
346
347   if (!image_type)
348     {
349       static const GtkTypeInfo image_info =
350       {
351         (gchar*)"CvImageWidget",
352         sizeof (CvImageWidget),
353         sizeof (CvImageWidgetClass),
354         (GtkClassInitFunc) cvImageWidget_class_init,
355         (GtkObjectInitFunc) cvImageWidget_init,
356         /* reserved_1 */ NULL,
357         /* reserved_1 */ NULL,
358         (GtkClassInitFunc) NULL
359       };
360
361       image_type = gtk_type_unique (GTK_TYPE_WIDGET, &image_info);
362     }
363
364   return image_type;
365 }
366 /////////////////////////////////////////////////////////////////////////////
367 // End CvImageWidget
368 /////////////////////////////////////////////////////////////////////////////
369
370
371 struct CvWindow;
372
373 typedef struct CvTrackbar
374 {
375     int signature;
376     GtkWidget* widget;
377     char* name;
378     CvTrackbar* next;
379     CvWindow* parent;
380     int* data;
381     int pos;
382     int maxval;
383     CvTrackbarCallback notify;
384     CvTrackbarCallback2 notify2;
385     void* userdata;
386 }
387 CvTrackbar;
388
389
390 typedef struct CvWindow
391 {
392     int signature;
393     GtkWidget* widget;
394     GtkWidget* frame;
395     GtkWidget* paned;
396     char* name;
397     CvWindow* prev;
398     CvWindow* next;
399
400     int last_key;
401     int flags;
402     int status;//0 normal, 1 fullscreen (YV)
403
404     CvMouseCallback on_mouse;
405     void* on_mouse_param;
406
407     struct
408     {
409         int pos;
410         int rows;
411         CvTrackbar* first;
412     }
413     toolbar;
414
415 #ifdef HAVE_OPENGL
416     bool useGl;
417
418     CvOpenGlDrawCallback glDrawCallback;
419     void* glDrawData;
420 #endif
421 }
422 CvWindow;
423
424
425 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
426 static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
427 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
428 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
429
430 #ifdef HAVE_GTHREAD
431 int thread_started=0;
432 static gpointer icvWindowThreadLoop();
433 GMutex*                            last_key_mutex;
434 GCond*                             cond_have_key;
435 GMutex*                            window_mutex;
436 GThread*                           window_thread;
437 GtkWidget*             cvTopLevelWidget = 0;
438 #endif
439
440 static int             last_key = -1;
441 static CvWindow* hg_windows = 0;
442
443 CV_IMPL int cvInitSystem( int argc, char** argv )
444 {
445     static int wasInitialized = 0;
446
447     // check initialization status
448     if( !wasInitialized )
449     {
450         hg_windows = 0;
451
452         gtk_disable_setlocale();
453         gtk_init( &argc, &argv );
454
455         #ifdef HAVE_OPENGL
456             gtk_gl_init(&argc, &argv);
457         #endif
458
459         wasInitialized = 1;
460     }
461
462     return 0;
463 }
464
465 CV_IMPL int cvStartWindowThread(){
466 #ifdef HAVE_GTHREAD
467     cvInitSystem(0,NULL);
468     if (!thread_started) {
469     if (!g_thread_supported ()) {
470         /* the GThread system wasn't inited, so init it */
471         g_thread_init(NULL);
472     }
473
474     // this mutex protects the window resources
475     window_mutex = g_mutex_new();
476
477     // protects the 'last key pressed' variable
478     last_key_mutex = g_mutex_new();
479
480     // conditional that indicates a key has been pressed
481     cond_have_key = g_cond_new();
482
483     // this is the window update thread
484     window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
485                     NULL, TRUE, NULL);
486     }
487     thread_started = window_thread!=NULL;
488     return thread_started;
489 #else
490     return 0;
491 #endif
492 }
493
494 #ifdef HAVE_GTHREAD
495 gpointer icvWindowThreadLoop(){
496     while(1){
497         g_mutex_lock(window_mutex);
498         gtk_main_iteration_do(FALSE);
499         g_mutex_unlock(window_mutex);
500
501         // little sleep
502         g_usleep(500);
503
504         g_thread_yield();
505     }
506     return NULL;
507 }
508
509 #define CV_LOCK_MUTEX() \
510 if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { }
511
512 #define CV_UNLOCK_MUTEX() \
513 if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { }
514
515 #else
516 #define CV_LOCK_MUTEX()
517 #define CV_UNLOCK_MUTEX()
518 #endif
519
520 static CvWindow* icvFindWindowByName( const char* name )
521 {
522     CvWindow* window = hg_windows;
523     while( window != 0 && strcmp(name, window->name) != 0 )
524         window = window->next;
525
526     return window;
527 }
528
529 static CvWindow* icvWindowByWidget( GtkWidget* widget )
530 {
531     CvWindow* window = hg_windows;
532
533     while( window != 0 && window->widget != widget &&
534            window->frame != widget && window->paned != widget )
535         window = window->next;
536
537     return window;
538 }
539
540 double cvGetModeWindow_GTK(const char* name)//YV
541 {
542     double result = -1;
543
544     CV_FUNCNAME( "cvGetModeWindow_GTK" );
545
546     __BEGIN__;
547
548     CvWindow* window;
549
550     if (!name)
551         CV_ERROR( CV_StsNullPtr, "NULL name string" );
552
553     window = icvFindWindowByName( name );
554     if (!window)
555         CV_ERROR( CV_StsNullPtr, "NULL window" );
556
557     CV_LOCK_MUTEX();
558     result = window->status;
559     CV_UNLOCK_MUTEX();
560
561     __END__;
562     return result;
563 }
564
565
566 void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
567 {
568
569     CV_FUNCNAME( "cvSetModeWindow_GTK" );
570
571     __BEGIN__;
572
573     CvWindow* window;
574
575     if(!name)
576         CV_ERROR( CV_StsNullPtr, "NULL name string" );
577
578     window = icvFindWindowByName( name );
579     if( !window )
580         CV_ERROR( CV_StsNullPtr, "NULL window" );
581
582     if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
583         EXIT;
584
585     //so easy to do fullscreen here, Linux rocks !
586
587     if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
588     {
589         CV_LOCK_MUTEX();
590         gtk_window_unfullscreen(GTK_WINDOW(window->frame));
591         window->status=CV_WINDOW_NORMAL;
592         CV_UNLOCK_MUTEX();
593         EXIT;
594     }
595
596     if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
597     {
598         CV_LOCK_MUTEX();
599         gtk_window_fullscreen(GTK_WINDOW(window->frame));
600         window->status=CV_WINDOW_FULLSCREEN;
601         CV_UNLOCK_MUTEX();
602         EXIT;
603     }
604
605     __END__;
606 }
607
608
609 double cvGetPropWindowAutoSize_GTK(const char* name)
610 {
611     double result = -1;
612
613     CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" );
614
615     __BEGIN__;
616
617     CvWindow* window;
618
619     if (!name)
620         CV_ERROR( CV_StsNullPtr, "NULL name string" );
621
622     window = icvFindWindowByName( name );
623     if (!window)
624         EXIT; // keep silence here
625
626     result = window->flags & CV_WINDOW_AUTOSIZE;
627
628     __END__;
629
630     return result;
631 }
632
633 double cvGetRatioWindow_GTK(const char* name)
634 {
635     double result = -1;
636
637     CV_FUNCNAME( "cvGetRatioWindow_GTK" );
638
639     __BEGIN__;
640
641     CvWindow* window;
642
643     if (!name)
644         CV_ERROR( CV_StsNullPtr, "NULL name string" );
645
646     window = icvFindWindowByName( name );
647     if (!window)
648         EXIT; // keep silence here
649
650     result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
651
652     __END__;
653
654     return result;
655 }
656
657 double cvGetOpenGlProp_GTK(const char* name)
658 {
659     double result = -1;
660
661 #ifdef HAVE_OPENGL
662     CV_FUNCNAME( "cvGetOpenGlProp_GTK" );
663
664     __BEGIN__;
665
666     CvWindow* window;
667
668     if (!name)
669         CV_ERROR( CV_StsNullPtr, "NULL name string" );
670
671     window = icvFindWindowByName( name );
672     if (!window)
673         EXIT; // keep silence here
674
675     result = window->useGl;
676
677     __END__;
678 #else
679     (void)name;
680 #endif
681
682     return result;
683 }
684
685
686 // OpenGL support
687
688 #ifdef HAVE_OPENGL
689
690 namespace
691 {
692     void createGlContext(CvWindow* window)
693     {
694         GdkGLConfig* glconfig;
695
696         CV_FUNCNAME( "createGlContext" );
697
698         __BEGIN__;
699
700         // Try double-buffered visual
701         glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
702         if (!glconfig)
703             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
704
705         // Set OpenGL-capability to the widget
706         if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))
707             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
708
709         window->useGl = true;
710
711         __END__;
712     }
713
714     void drawGl(CvWindow* window)
715     {
716         CV_FUNCNAME( "drawGl" );
717
718         __BEGIN__;
719
720         GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
721         GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
722
723         if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
724             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
725
726         glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);
727
728         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
729
730         if (window->glDrawCallback)
731             window->glDrawCallback(window->glDrawData);
732
733         if (gdk_gl_drawable_is_double_buffered (gldrawable))
734             gdk_gl_drawable_swap_buffers(gldrawable);
735         else
736             glFlush();
737
738         gdk_gl_drawable_gl_end(gldrawable);
739
740         __END__;
741     }
742 }
743
744 #endif // HAVE_OPENGL
745
746
747 static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
748 {
749 #ifdef HAVE_OPENGL
750     CvWindow* window = (CvWindow*)data;
751
752     if (window->useGl)
753     {
754         drawGl(window);
755         return TRUE;
756     }
757 #else
758     (void)data;
759 #endif
760
761   CvImageWidget *image_widget;
762
763   g_return_val_if_fail (widget != NULL, FALSE);
764   g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
765   g_return_val_if_fail (event != NULL, FALSE);
766
767   if (event->count > 0)
768     return FALSE;
769
770   image_widget = CV_IMAGE_WIDGET (widget);
771
772   gdk_window_clear_area (widget->window,
773                          0, 0,
774                          widget->allocation.width,
775                          widget->allocation.height);
776   if( image_widget->scaled_image ){
777       // center image in available region
778       int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
779       int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
780
781       gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
782           x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
783           MIN(image_widget->scaled_image->rows, widget->allocation.height),
784           GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
785   }
786   else if( image_widget->original_image ){
787       gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
788           0, 0,
789           MIN(image_widget->original_image->cols, widget->allocation.width),
790            MIN(image_widget->original_image->rows, widget->allocation.height),
791           GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
792   }
793   return TRUE;
794 }
795
796 CV_IMPL int cvNamedWindow( const char* name, int flags )
797 {
798     int result = 0;
799     CV_FUNCNAME( "cvNamedWindow" );
800
801     __BEGIN__;
802
803     CvWindow* window;
804     int len;
805
806     cvInitSystem(1,(char**)&name);
807     if( !name )
808         CV_ERROR( CV_StsNullPtr, "NULL name string" );
809
810     // Check the name in the storage
811     if( icvFindWindowByName( name ) != 0 )
812     {
813         result = 1;
814         EXIT;
815     }
816
817     len = strlen(name);
818     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
819     memset( window, 0, sizeof(*window));
820     window->name = (char*)(window + 1);
821     memcpy( window->name, name, len + 1 );
822     window->flags = flags;
823     window->signature = CV_WINDOW_MAGIC_VAL;
824     window->last_key = 0;
825     window->on_mouse = 0;
826     window->on_mouse_param = 0;
827     memset( &window->toolbar, 0, sizeof(window->toolbar));
828     window->next = hg_windows;
829     window->prev = 0;
830     window->status = CV_WINDOW_NORMAL;//YV
831
832     CV_LOCK_MUTEX();
833
834     window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
835
836     window->paned = gtk_vbox_new( FALSE, 0 );
837     window->widget = cvImageWidgetNew( flags );
838     gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
839     gtk_widget_show( window->widget );
840     gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
841     gtk_widget_show( window->paned );
842
843 #ifndef HAVE_OPENGL
844     if (flags & CV_WINDOW_OPENGL)
845         CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
846 #else
847     if (flags & CV_WINDOW_OPENGL)
848         createGlContext(window);
849
850     window->glDrawCallback = 0;
851     window->glDrawData = 0;
852 #endif
853
854     //
855     // configure event handlers
856     // TODO -- move this to CvImageWidget ?
857     gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event",
858                         GTK_SIGNAL_FUNC(icvOnKeyPress), window );
859     gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event",
860                         GTK_SIGNAL_FUNC(icvOnMouse), window );
861     gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event",
862                         GTK_SIGNAL_FUNC(icvOnMouse), window );
863     gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event",
864                         GTK_SIGNAL_FUNC(icvOnMouse), window );
865     gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event",
866                         GTK_SIGNAL_FUNC(icvOnClose), window );
867     gtk_signal_connect( GTK_OBJECT(window->widget), "expose-event",
868                         GTK_SIGNAL_FUNC(cvImageWidget_expose), window );
869
870     gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
871
872     gtk_widget_show( window->frame );
873     gtk_window_set_title( GTK_WINDOW(window->frame), name );
874
875     if( hg_windows )
876         hg_windows->prev = window;
877     hg_windows = window;
878
879     gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
880
881
882     // allow window to be resized
883     if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
884         GdkGeometry geometry;
885         geometry.min_width = 50;
886         geometry.min_height = 50;
887         gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
888             &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
889     }
890
891     CV_UNLOCK_MUTEX();
892
893 #ifdef HAVE_OPENGL
894     if (window->useGl)
895         cvSetOpenGlContext(name);
896 #endif
897
898     result = 1;
899     __END__;
900
901     return result;
902 }
903
904
905 #ifdef HAVE_OPENGL
906
907 CV_IMPL void cvSetOpenGlContext(const char* name)
908 {
909     CvWindow* window;
910     GdkGLContext* glcontext;
911     GdkGLDrawable* gldrawable;
912
913     CV_FUNCNAME( "cvSetOpenGlContext" );
914
915     __BEGIN__;
916
917     if(!name)
918         CV_ERROR( CV_StsNullPtr, "NULL name string" );
919
920     window = icvFindWindowByName( name );
921     if (!window)
922         CV_ERROR( CV_StsNullPtr, "NULL window" );
923
924     if (!window->useGl)
925         CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
926
927     glcontext = gtk_widget_get_gl_context(window->widget);
928     gldrawable = gtk_widget_get_gl_drawable(window->widget);
929
930     if (!gdk_gl_drawable_make_current(gldrawable, glcontext))
931         CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
932
933     __END__;
934 }
935
936 CV_IMPL void cvUpdateWindow(const char* name)
937 {
938     CV_FUNCNAME( "cvUpdateWindow" );
939
940     __BEGIN__;
941
942     CvWindow* window;
943
944     if (!name)
945         CV_ERROR( CV_StsNullPtr, "NULL name string" );
946
947     window = icvFindWindowByName( name );
948     if (!window)
949         EXIT;
950
951     // window does not refresh without this
952     gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
953
954     __END__;
955 }
956
957 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
958 {
959     CvWindow* window;
960
961     CV_FUNCNAME( "cvCreateOpenGLCallback" );
962
963     __BEGIN__;
964
965     if(!name)
966         CV_ERROR( CV_StsNullPtr, "NULL name string" );
967
968     window = icvFindWindowByName( name );
969     if( !window )
970         EXIT;
971
972     if (!window->useGl)
973         CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
974
975     window->glDrawCallback = callback;
976     window->glDrawData = userdata;
977
978     __END__;
979 }
980
981 #endif // HAVE_OPENGL
982
983
984
985
986 static void icvDeleteWindow( CvWindow* window )
987 {
988     CvTrackbar* trackbar;
989
990     if( window->prev )
991         window->prev->next = window->next;
992     else
993         hg_windows = window->next;
994
995     if( window->next )
996         window->next->prev = window->prev;
997
998     window->prev = window->next = 0;
999
1000     gtk_widget_destroy( window->frame );
1001
1002     for( trackbar = window->toolbar.first; trackbar != 0; )
1003     {
1004         CvTrackbar* next = trackbar->next;
1005         cvFree( &trackbar );
1006         trackbar = next;
1007     }
1008
1009     cvFree( &window );
1010 #ifdef HAVE_GTHREAD
1011     // if last window, send key press signal
1012     // to jump out of any waiting cvWaitKey's
1013     if(hg_windows==0 && thread_started){
1014         g_cond_broadcast(cond_have_key);
1015     }
1016 #endif
1017 }
1018
1019
1020 CV_IMPL void cvDestroyWindow( const char* name )
1021 {
1022     CV_FUNCNAME( "cvDestroyWindow" );
1023
1024     __BEGIN__;
1025
1026     CvWindow* window;
1027
1028     if(!name)
1029         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1030
1031     window = icvFindWindowByName( name );
1032     if( !window )
1033         EXIT;
1034
1035     // note that it is possible for the update thread to run this function
1036     // if there is a call to cvShowImage in a mouse callback
1037     // (this would produce a deadlock on window_mutex)
1038     CV_LOCK_MUTEX();
1039
1040     icvDeleteWindow( window );
1041
1042     CV_UNLOCK_MUTEX();
1043
1044     __END__;
1045 }
1046
1047
1048 CV_IMPL void
1049 cvDestroyAllWindows( void )
1050 {
1051     CV_LOCK_MUTEX();
1052
1053     while( hg_windows )
1054     {
1055         CvWindow* window = hg_windows;
1056         icvDeleteWindow( window );
1057     }
1058     CV_UNLOCK_MUTEX();
1059 }
1060
1061 // CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
1062 //     CvSize window_size;
1063 //     GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
1064 //     gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
1065 //             &window_size.width, &window_size.height );
1066
1067 //     window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
1068 //     window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
1069
1070 //     return window_size;
1071 // }
1072
1073 CV_IMPL void
1074 cvShowImage( const char* name, const CvArr* arr )
1075 {
1076     CV_FUNCNAME( "cvShowImage" );
1077
1078     __BEGIN__;
1079
1080     CvWindow* window;
1081
1082     if( !name )
1083         CV_ERROR( CV_StsNullPtr, "NULL name" );
1084
1085     CV_LOCK_MUTEX();
1086
1087     window = icvFindWindowByName(name);
1088     if(!window)
1089     {
1090         cvNamedWindow(name, 1);
1091         window = icvFindWindowByName(name);
1092     }
1093
1094     if( window && arr )
1095     {
1096     #ifdef HAVE_OPENGL
1097         if (window->useGl)
1098         {
1099             CvMat stub;
1100             CvMat* mat = cvGetMat(arr, &stub);
1101             cv::Mat im(mat);
1102             cv::imshow(name, im);
1103             return;
1104         }
1105     #endif
1106
1107         CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
1108         cvImageWidgetSetImage( image_widget, arr );
1109     }
1110
1111     CV_UNLOCK_MUTEX();
1112
1113     __END__;
1114 }
1115
1116 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1117 {
1118     CV_FUNCNAME( "cvResizeWindow" );
1119
1120     __BEGIN__;
1121
1122     CvWindow* window;
1123     CvImageWidget * image_widget;
1124
1125     if( !name )
1126         CV_ERROR( CV_StsNullPtr, "NULL name" );
1127
1128     window = icvFindWindowByName(name);
1129     if(!window)
1130         EXIT;
1131
1132     image_widget = CV_IMAGE_WIDGET( window->widget );
1133     //if(image_widget->flags & CV_WINDOW_AUTOSIZE)
1134         //EXIT;
1135
1136     CV_LOCK_MUTEX();
1137
1138     gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
1139     gtk_window_resize( GTK_WINDOW(window->frame), width, height );
1140
1141     // disable initial resize since presumably user wants to keep
1142     // this window size
1143     image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
1144
1145     CV_UNLOCK_MUTEX();
1146
1147     __END__;
1148 }
1149
1150
1151 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1152 {
1153     CV_FUNCNAME( "cvMoveWindow" );
1154
1155     __BEGIN__;
1156
1157     CvWindow* window;
1158
1159     if( !name )
1160         CV_ERROR( CV_StsNullPtr, "NULL name" );
1161
1162     window = icvFindWindowByName(name);
1163     if(!window)
1164         EXIT;
1165
1166     CV_LOCK_MUTEX();
1167
1168     gtk_window_move( GTK_WINDOW(window->frame), x, y );
1169
1170     CV_UNLOCK_MUTEX();
1171
1172     __END__;
1173 }
1174
1175
1176 static CvTrackbar*
1177 icvFindTrackbarByName( const CvWindow* window, const char* name )
1178 {
1179     CvTrackbar* trackbar = window->toolbar.first;
1180
1181     for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1182         ;
1183
1184     return trackbar;
1185 }
1186
1187 static int
1188 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
1189                    int* val, int count, CvTrackbarCallback on_notify,
1190                    CvTrackbarCallback2 on_notify2, void* userdata )
1191 {
1192     int result = 0;
1193
1194     CV_FUNCNAME( "icvCreateTrackbar" );
1195
1196     __BEGIN__;
1197
1198     /*char slider_name[32];*/
1199     CvWindow* window = 0;
1200     CvTrackbar* trackbar = 0;
1201
1202     if( !window_name || !trackbar_name )
1203         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
1204
1205     if( count <= 0 )
1206         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
1207
1208     window = icvFindWindowByName(window_name);
1209     if( !window )
1210         EXIT;
1211
1212     trackbar = icvFindTrackbarByName(window,trackbar_name);
1213
1214     CV_LOCK_MUTEX();
1215
1216     if( !trackbar )
1217     {
1218         int len = strlen(trackbar_name);
1219         trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
1220         memset( trackbar, 0, sizeof(*trackbar));
1221         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
1222         trackbar->name = (char*)(trackbar+1);
1223         memcpy( trackbar->name, trackbar_name, len + 1 );
1224         trackbar->parent = window;
1225         trackbar->next = window->toolbar.first;
1226         window->toolbar.first = trackbar;
1227
1228         GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
1229         GtkWidget* hscale_label = gtk_label_new( trackbar_name );
1230         GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
1231         gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS );
1232         gtk_scale_set_digits( GTK_SCALE(hscale), 0 );
1233         //gtk_scale_set_value_pos( hscale, GTK_POS_TOP );
1234         gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );
1235
1236         trackbar->widget = hscale;
1237         gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );
1238         gtk_widget_show( hscale_label );
1239         gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );
1240         gtk_widget_show( hscale );
1241         gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );
1242         gtk_widget_show( hscale_box );
1243
1244     }
1245
1246     if( val )
1247     {
1248         int value = *val;
1249         if( value < 0 )
1250             value = 0;
1251         if( value > count )
1252             value = count;
1253         gtk_range_set_value( GTK_RANGE(trackbar->widget), value );
1254         trackbar->pos = value;
1255         trackbar->data = val;
1256     }
1257
1258     trackbar->maxval = count;
1259     trackbar->notify = on_notify;
1260     trackbar->notify2 = on_notify2;
1261     trackbar->userdata = userdata;
1262     gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed",
1263                         GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar );
1264
1265     // queue a widget resize to trigger a window resize to
1266     // compensate for the addition of trackbars
1267     gtk_widget_queue_resize( GTK_WIDGET(window->widget) );
1268
1269
1270     CV_UNLOCK_MUTEX();
1271
1272     result = 1;
1273
1274     __END__;
1275
1276     return result;
1277 }
1278
1279
1280 CV_IMPL int
1281 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1282                   int* val, int count, CvTrackbarCallback on_notify )
1283 {
1284     return icvCreateTrackbar(trackbar_name, window_name, val, count,
1285                              on_notify, 0, 0);
1286 }
1287
1288
1289 CV_IMPL int
1290 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
1291                    int* val, int count, CvTrackbarCallback2 on_notify2,
1292                    void* userdata )
1293 {
1294     return icvCreateTrackbar(trackbar_name, window_name, val, count,
1295                              0, on_notify2, userdata);
1296 }
1297
1298
1299 CV_IMPL void
1300 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1301 {
1302     CV_FUNCNAME( "cvSetMouseCallback" );
1303
1304     __BEGIN__;
1305
1306     CvWindow* window = 0;
1307
1308     if( !window_name )
1309         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1310
1311     window = icvFindWindowByName(window_name);
1312     if( !window )
1313         EXIT;
1314
1315     window->on_mouse = on_mouse;
1316     window->on_mouse_param = param;
1317
1318     __END__;
1319 }
1320
1321
1322 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1323 {
1324     int pos = -1;
1325
1326     CV_FUNCNAME( "cvGetTrackbarPos" );
1327
1328     __BEGIN__;
1329
1330     CvWindow* window;
1331     CvTrackbar* trackbar = 0;
1332
1333     if( trackbar_name == 0 || window_name == 0 )
1334         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1335
1336     window = icvFindWindowByName( window_name );
1337     if( window )
1338         trackbar = icvFindTrackbarByName( window, trackbar_name );
1339
1340     if( trackbar )
1341         pos = trackbar->pos;
1342
1343     __END__;
1344
1345     return pos;
1346 }
1347
1348
1349 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1350 {
1351     CV_FUNCNAME( "cvSetTrackbarPos" );
1352
1353     __BEGIN__;
1354
1355     CvWindow* window;
1356     CvTrackbar* trackbar = 0;
1357
1358     if( trackbar_name == 0 || window_name == 0 )
1359         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1360
1361     window = icvFindWindowByName( window_name );
1362     if( window )
1363         trackbar = icvFindTrackbarByName( window, trackbar_name );
1364
1365     if( trackbar )
1366     {
1367         if( pos < 0 )
1368             pos = 0;
1369
1370         if( pos > trackbar->maxval )
1371             pos = trackbar->maxval;
1372     }
1373
1374     CV_LOCK_MUTEX();
1375
1376     gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
1377
1378     CV_UNLOCK_MUTEX();
1379
1380     __END__;
1381 }
1382
1383
1384 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1385 {
1386     void* widget = 0;
1387
1388     CV_FUNCNAME( "cvGetWindowHandle" );
1389
1390     __BEGIN__;
1391
1392     CvWindow* window;
1393
1394     if( window_name == 0 )
1395         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1396
1397     window = icvFindWindowByName( window_name );
1398     if( window )
1399         widget = (void*)window->widget;
1400
1401     __END__;
1402
1403     return widget;
1404 }
1405
1406
1407 CV_IMPL const char* cvGetWindowName( void* window_handle )
1408 {
1409     const char* window_name = "";
1410
1411     CV_FUNCNAME( "cvGetWindowName" );
1412
1413     __BEGIN__;
1414
1415     CvWindow* window;
1416
1417     if( window_handle == 0 )
1418         CV_ERROR( CV_StsNullPtr, "NULL window" );
1419
1420     window = icvWindowByWidget( (GtkWidget*)window_handle );
1421     if( window )
1422         window_name = window->name;
1423
1424     __END__;
1425
1426     return window_name;
1427 }
1428
1429 static gboolean icvOnKeyPress( GtkWidget * /*widget*/,
1430                 GdkEventKey* event, gpointer /*user_data*/ )
1431 {
1432     int code = 0;
1433
1434     switch( event->keyval )
1435     {
1436     case GDK_Escape:
1437         code = 27;
1438         break;
1439     case GDK_Return:
1440     case GDK_Linefeed:
1441         code = '\n';
1442         break;
1443     case GDK_Tab:
1444         code = '\t';
1445     break;
1446     default:
1447         code = event->keyval;
1448     }
1449
1450     code |= event->state << 16;
1451
1452 #ifdef HAVE_GTHREAD
1453     if(thread_started) g_mutex_lock(last_key_mutex);
1454 #endif
1455
1456     last_key = code;
1457
1458 #ifdef HAVE_GTHREAD
1459     if(thread_started){
1460         // signal any waiting threads
1461         g_cond_broadcast(cond_have_key);
1462         g_mutex_unlock(last_key_mutex);
1463     }
1464 #endif
1465
1466     return FALSE;
1467 }
1468
1469
1470 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
1471 {
1472     int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
1473     CvTrackbar* trackbar = (CvTrackbar*)user_data;
1474
1475     if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
1476         trackbar->widget == widget )
1477     {
1478         trackbar->pos = pos;
1479         if( trackbar->data )
1480             *trackbar->data = pos;
1481         if( trackbar->notify2 )
1482             trackbar->notify2(pos, trackbar->userdata);
1483         else if( trackbar->notify )
1484             trackbar->notify(pos);
1485     }
1486 }
1487
1488 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
1489 {
1490     CvWindow* window = (CvWindow*)user_data;
1491     if( window->signature == CV_WINDOW_MAGIC_VAL &&
1492         window->frame == widget )
1493     {
1494         icvDeleteWindow(window);
1495     }
1496     return TRUE;
1497 }
1498
1499
1500 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
1501 {
1502     // TODO move this logic to CvImageWidget
1503     CvWindow* window = (CvWindow*)user_data;
1504     CvPoint2D32f pt32f = {-1., -1.};
1505     CvPoint pt = {-1,-1};
1506     int cv_event = -1, state = 0;
1507     CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
1508
1509     if( window->signature != CV_WINDOW_MAGIC_VAL ||
1510         window->widget != widget || !window->widget ||
1511         !window->on_mouse /*|| !image_widget->original_image*/)
1512         return FALSE;
1513
1514     if( event->type == GDK_MOTION_NOTIFY )
1515     {
1516         GdkEventMotion* event_motion = (GdkEventMotion*)event;
1517
1518         cv_event = CV_EVENT_MOUSEMOVE;
1519         pt32f.x = cvRound(event_motion->x);
1520         pt32f.y = cvRound(event_motion->y);
1521         state = event_motion->state;
1522     }
1523     else if( event->type == GDK_BUTTON_PRESS ||
1524              event->type == GDK_BUTTON_RELEASE ||
1525              event->type == GDK_2BUTTON_PRESS )
1526     {
1527         GdkEventButton* event_button = (GdkEventButton*)event;
1528         pt32f.x = cvRound(event_button->x);
1529         pt32f.y = cvRound(event_button->y);
1530
1531
1532         if( event_button->type == GDK_BUTTON_PRESS )
1533         {
1534             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
1535                        event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
1536                        event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
1537         }
1538         else if( event_button->type == GDK_BUTTON_RELEASE )
1539         {
1540             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
1541                        event_button->button == 2 ? CV_EVENT_MBUTTONUP :
1542                        event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
1543         }
1544         else if( event_button->type == GDK_2BUTTON_PRESS )
1545         {
1546             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
1547                        event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
1548                        event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
1549         }
1550         state = event_button->state;
1551     }
1552
1553     if( cv_event >= 0 ){
1554         // scale point if image is scaled
1555         if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
1556              image_widget->original_image &&
1557              image_widget->scaled_image ){
1558             // image origin is not necessarily at (0,0)
1559             int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1560             int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1561             pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/
1562                                             image_widget->scaled_image->cols );
1563             pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/
1564                                             image_widget->scaled_image->rows );
1565         }
1566         else{
1567             pt = cvPointFrom32f( pt32f );
1568         }
1569
1570 //        if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
1571 //           (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
1572         {
1573             int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
1574                 (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
1575                 (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
1576                 (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
1577                 (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
1578                 (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
1579             window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
1580         }
1581     }
1582
1583         return FALSE;
1584     }
1585
1586
1587 static gboolean icvAlarm( gpointer user_data )
1588 {
1589     *(int*)user_data = 1;
1590     return FALSE;
1591 }
1592
1593
1594 CV_IMPL int cvWaitKey( int delay )
1595 {
1596 #ifdef HAVE_GTHREAD
1597     if(thread_started && g_thread_self()!=window_thread){
1598         gboolean expired;
1599         int my_last_key;
1600
1601         // wait for signal or timeout if delay > 0
1602         if(delay>0){
1603             GTimeVal timer;
1604             g_get_current_time(&timer);
1605             g_time_val_add(&timer, delay*1000);
1606             expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
1607         }
1608         else{
1609             g_cond_wait(cond_have_key, last_key_mutex);
1610             expired=false;
1611         }
1612         my_last_key = last_key;
1613         g_mutex_unlock(last_key_mutex);
1614         if(expired || hg_windows==0){
1615             return -1;
1616         }
1617         return my_last_key;
1618     }
1619     else{
1620 #endif
1621         int expired = 0;
1622         guint timer = 0;
1623         if( delay > 0 )
1624             timer = g_timeout_add( delay, icvAlarm, &expired );
1625         last_key = -1;
1626         while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 )
1627             ;
1628
1629         if( delay > 0 && !expired )
1630             g_source_remove(timer);
1631 #ifdef HAVE_GTHREAD
1632     }
1633 #endif
1634     return last_key;
1635 }
1636
1637
1638 #endif  // HAVE_GTK
1639 #endif  // WIN32
1640
1641 /* End of file. */