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