Fixed some warnings and install problems on linux
[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 // 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
421     CvOpenGlCleanCallback glCleanCallback;
422     void* glCleanData;
423 #endif
424 }
425 CvWindow;
426
427
428 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
429 static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
430 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
431 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
432
433 #ifdef HAVE_GTHREAD
434 int thread_started=0;
435 static gpointer icvWindowThreadLoop();
436 GMutex*                            last_key_mutex;
437 GCond*                             cond_have_key;
438 GMutex*                            window_mutex;
439 GThread*                           window_thread;
440 GtkWidget*             cvTopLevelWidget = 0;
441 #endif
442
443 static int             last_key = -1;
444 static CvWindow* hg_windows = 0;
445
446 CV_IMPL int cvInitSystem( int argc, char** argv )
447 {
448     static int wasInitialized = 0;
449
450     // check initialization status
451     if( !wasInitialized )
452     {
453         hg_windows = 0;
454
455         gtk_disable_setlocale();
456         gtk_init( &argc, &argv );
457
458         #ifdef HAVE_OPENGL
459             gtk_gl_init(&argc, &argv);
460         #endif
461
462         wasInitialized = 1;
463     }
464
465     return 0;
466 }
467
468 CV_IMPL int cvStartWindowThread(){
469 #ifdef HAVE_GTHREAD
470     cvInitSystem(0,NULL);
471     if (!thread_started) {
472     if (!g_thread_supported ()) {
473         /* the GThread system wasn't inited, so init it */
474         g_thread_init(NULL);
475     }
476
477     // this mutex protects the window resources
478     window_mutex = g_mutex_new();
479
480     // protects the 'last key pressed' variable
481     last_key_mutex = g_mutex_new();
482
483     // conditional that indicates a key has been pressed
484     cond_have_key = g_cond_new();
485
486     // this is the window update thread
487     window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
488                     NULL, TRUE, NULL);
489     }
490     thread_started = window_thread!=NULL;
491     return thread_started;
492 #else
493     return 0;
494 #endif
495 }
496
497 #ifdef HAVE_GTHREAD
498 gpointer icvWindowThreadLoop(){
499     while(1){
500         g_mutex_lock(window_mutex);
501         gtk_main_iteration_do(FALSE);
502         g_mutex_unlock(window_mutex);
503
504         // little sleep
505         g_usleep(500);
506
507         g_thread_yield();
508     }
509     return NULL;
510 }
511
512 #define CV_LOCK_MUTEX() \
513 if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { }
514
515 #define CV_UNLOCK_MUTEX() \
516 if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { }
517
518 #else
519 #define CV_LOCK_MUTEX()
520 #define CV_UNLOCK_MUTEX()
521 #endif
522
523 static CvWindow* icvFindWindowByName( const char* name )
524 {
525     CvWindow* window = hg_windows;
526     while( window != 0 && strcmp(name, window->name) != 0 )
527         window = window->next;
528
529     return window;
530 }
531
532 static CvWindow* icvWindowByWidget( GtkWidget* widget )
533 {
534     CvWindow* window = hg_windows;
535
536     while( window != 0 && window->widget != widget &&
537            window->frame != widget && window->paned != widget )
538         window = window->next;
539
540     return window;
541 }
542
543 double cvGetModeWindow_GTK(const char* name)//YV
544 {
545     double result = -1;
546
547     CV_FUNCNAME( "cvGetModeWindow_GTK" );
548
549     __BEGIN__;
550
551     CvWindow* window;
552
553     if (!name)
554         CV_ERROR( CV_StsNullPtr, "NULL name string" );
555
556     window = icvFindWindowByName( name );
557     if (!window)
558         CV_ERROR( CV_StsNullPtr, "NULL window" );
559
560     CV_LOCK_MUTEX();
561     result = window->status;
562     CV_UNLOCK_MUTEX();
563
564     __END__;
565     return result;
566 }
567
568
569 void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
570 {
571
572     CV_FUNCNAME( "cvSetModeWindow_GTK" );
573
574     __BEGIN__;
575
576     CvWindow* window;
577
578     if(!name)
579         CV_ERROR( CV_StsNullPtr, "NULL name string" );
580
581     window = icvFindWindowByName( name );
582     if( !window )
583         CV_ERROR( CV_StsNullPtr, "NULL window" );
584
585     if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
586         EXIT;
587
588     //so easy to do fullscreen here, Linux rocks !
589
590     if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
591     {
592         CV_LOCK_MUTEX();
593         gtk_window_unfullscreen(GTK_WINDOW(window->frame));
594         window->status=CV_WINDOW_NORMAL;
595         CV_UNLOCK_MUTEX();
596         EXIT;
597     }
598
599     if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
600     {
601         CV_LOCK_MUTEX();
602         gtk_window_fullscreen(GTK_WINDOW(window->frame));
603         window->status=CV_WINDOW_FULLSCREEN;
604         CV_UNLOCK_MUTEX();
605         EXIT;
606     }
607
608     __END__;
609 }
610
611
612 double cvGetPropWindowAutoSize_GTK(const char* name)
613 {
614     double result = -1;
615
616     CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" );
617
618     __BEGIN__;
619
620     CvWindow* window;
621
622     if (!name)
623         CV_ERROR( CV_StsNullPtr, "NULL name string" );
624
625     window = icvFindWindowByName( name );
626     if (!window)
627         EXIT; // keep silence here
628
629     result = window->flags & CV_WINDOW_AUTOSIZE;
630
631     __END__;
632
633     return result;
634 }
635
636 double cvGetRatioWindow_GTK(const char* name)
637 {
638     double result = -1;
639
640     CV_FUNCNAME( "cvGetRatioWindow_GTK" );
641
642     __BEGIN__;
643
644     CvWindow* window;
645
646     if (!name)
647         CV_ERROR( CV_StsNullPtr, "NULL name string" );
648
649     window = icvFindWindowByName( name );
650     if (!window)
651         EXIT; // keep silence here
652
653     result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
654
655     __END__;
656
657     return result;
658 }
659
660 double cvGetOpenGlProp_GTK(const char* name)
661 {
662     double result = -1;
663
664 #ifdef HAVE_OPENGL
665     CV_FUNCNAME( "cvGetOpenGlProp_GTK" );
666
667     __BEGIN__;
668
669     CvWindow* window;
670
671     if (!name)
672         CV_ERROR( CV_StsNullPtr, "NULL name string" );
673
674     window = icvFindWindowByName( name );
675     if (!window)
676         EXIT; // keep silence here
677
678     result = window->useGl;
679
680     __END__;
681 #else
682     (void)name;
683 #endif
684
685     return result;
686 }
687
688
689 // OpenGL support
690
691 #ifdef HAVE_OPENGL
692
693 namespace
694 {
695     class GlFuncTab_GTK : public CvOpenGlFuncTab
696     {
697     public:
698         GlFuncTab_GTK();
699
700         void genBuffers(int n, unsigned int* buffers) const;
701         void deleteBuffers(int n, const unsigned int* buffers) const;
702
703         void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const;
704         void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const;
705
706         void bindBuffer(unsigned int target, unsigned int buffer) const;
707
708         void* mapBuffer(unsigned int target, unsigned int access) const;
709         void unmapBuffer(unsigned int target) const;
710
711         void generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const;
712
713         bool isGlContextInitialized() const;
714
715         PFNGLGENBUFFERSPROC    glGenBuffersExt;
716         PFNGLDELETEBUFFERSPROC glDeleteBuffersExt;
717
718         PFNGLBUFFERDATAPROC    glBufferDataExt;
719         PFNGLBUFFERSUBDATAPROC glBufferSubDataExt;
720
721         PFNGLBINDBUFFERPROC    glBindBufferExt;
722
723         PFNGLMAPBUFFERPROC     glMapBufferExt;
724         PFNGLUNMAPBUFFERPROC   glUnmapBufferExt;
725
726         bool initialized;
727     };
728
729     GlFuncTab_GTK::GlFuncTab_GTK()
730     {
731         glGenBuffersExt    = 0;
732         glDeleteBuffersExt = 0;
733
734         glBufferDataExt    = 0;
735         glBufferSubDataExt = 0;
736
737         glBindBufferExt    = 0;
738
739         glMapBufferExt     = 0;
740         glUnmapBufferExt   = 0;
741
742         initialized = false;
743     }
744
745     void GlFuncTab_GTK::genBuffers(int n, unsigned int* buffers) const
746     {
747         CV_FUNCNAME( "GlFuncTab_GTK::genBuffers" );
748
749         __BEGIN__;
750
751         if (!glGenBuffersExt)
752             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
753
754         glGenBuffersExt(n, buffers);
755         CV_CheckGlError();
756
757         __END__;
758     }
759
760     void GlFuncTab_GTK::deleteBuffers(int n, const unsigned int* buffers) const
761     {
762         CV_FUNCNAME( "GlFuncTab_GTK::deleteBuffers" );
763
764         __BEGIN__;
765
766         if (!glDeleteBuffersExt)
767             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
768
769         glDeleteBuffersExt(n, buffers);
770         CV_CheckGlError();
771
772         __END__;
773     }
774
775     void GlFuncTab_GTK::bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const
776     {
777         CV_FUNCNAME( "GlFuncTab_GTK::bufferData" );
778
779         __BEGIN__;
780
781         if (!glBufferDataExt)
782             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
783
784         glBufferDataExt(target, size, data, usage);
785         CV_CheckGlError();
786
787         __END__;
788     }
789
790     void GlFuncTab_GTK::bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const
791     {
792         CV_FUNCNAME( "GlFuncTab_GTK::bufferSubData" );
793
794         __BEGIN__;
795
796         if (!glBufferSubDataExt)
797             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
798
799         glBufferSubDataExt(target, offset, size, data);
800         CV_CheckGlError();
801
802         __END__;
803     }
804
805     void GlFuncTab_GTK::bindBuffer(unsigned int target, unsigned int buffer) const
806     {
807         CV_FUNCNAME( "GlFuncTab_GTK::bindBuffer" );
808
809         __BEGIN__;
810
811         if (!glBindBufferExt)
812             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
813
814         glBindBufferExt(target, buffer);
815         CV_CheckGlError();
816
817         __END__;
818     }
819
820     void* GlFuncTab_GTK::mapBuffer(unsigned int target, unsigned int access) const
821     {
822         CV_FUNCNAME( "GlFuncTab_GTK::mapBuffer" );
823
824         void* res = 0;
825
826         __BEGIN__;
827
828         if (!glMapBufferExt)
829             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
830
831         res = glMapBufferExt(target, access);
832         CV_CheckGlError();
833
834         __END__;
835
836         return res;
837     }
838
839     void GlFuncTab_GTK::unmapBuffer(unsigned int target) const
840     {
841         CV_FUNCNAME( "GlFuncTab_GTK::unmapBuffer" );
842
843         __BEGIN__;
844
845         if (!glUnmapBufferExt)
846             CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
847
848         glUnmapBufferExt(target);
849         CV_CheckGlError();
850
851         __END__;
852     }
853
854     void GlFuncTab_GTK::generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool /*underline*/, int start, int count, int base) const
855     {
856         PangoFontDescription* fontDecr;
857         PangoFont* pangoFont;
858
859         CV_FUNCNAME( "GlFuncTab_GTK::generateBitmapFont" );
860
861         __BEGIN__;
862
863         fontDecr = pango_font_description_new();
864
865         pango_font_description_set_size(fontDecr, height);
866
867         pango_font_description_set_family_static(fontDecr, family.c_str());
868
869         pango_font_description_set_weight(fontDecr, static_cast<PangoWeight>(weight));
870
871         pango_font_description_set_style(fontDecr, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
872
873         pangoFont = gdk_gl_font_use_pango_font(fontDecr, start, count, base);
874
875         pango_font_description_free(fontDecr);
876
877         if (!pangoFont)
878             CV_ERROR(CV_OpenGlApiCallError, "Can't create font");
879
880         __END__;
881     }
882
883     bool GlFuncTab_GTK::isGlContextInitialized() const
884     {
885         return initialized;
886     }
887
888     void initGl()
889     {
890         static GlFuncTab_GTK glFuncTab;
891         static bool first = true;
892
893         if (first)
894         {
895             // Load extensions
896             GdkGLProc func;
897
898             func = gdk_gl_get_proc_address("glGenBuffers");
899             glFuncTab.glGenBuffersExt = (PFNGLGENBUFFERSPROC)func;
900
901             func = gdk_gl_get_proc_address("glDeleteBuffers");
902             glFuncTab.glDeleteBuffersExt = (PFNGLDELETEBUFFERSPROC)func;
903
904             func = gdk_gl_get_proc_address("glBufferData");
905             glFuncTab.glBufferDataExt = (PFNGLBUFFERDATAPROC)func;
906
907             func = gdk_gl_get_proc_address("glBufferSubData");
908             glFuncTab.glBufferSubDataExt = (PFNGLBUFFERSUBDATAPROC)func;
909
910             func = gdk_gl_get_proc_address("glBindBuffer");
911             glFuncTab.glBindBufferExt = (PFNGLBINDBUFFERPROC)func;
912
913             func = gdk_gl_get_proc_address("glMapBuffer");
914             glFuncTab.glMapBufferExt = (PFNGLMAPBUFFERPROC)func;
915
916             func = gdk_gl_get_proc_address("glUnmapBuffer");
917             glFuncTab.glUnmapBufferExt = (PFNGLUNMAPBUFFERPROC)func;
918
919             glFuncTab.initialized = true;
920
921             icvSetOpenGlFuncTab(&glFuncTab);
922
923             first = false;
924         }
925     }
926
927     void createGlContext(CvWindow* window)
928     {
929         GdkGLConfig* glconfig;
930
931         CV_FUNCNAME( "createGlContext" );
932
933         __BEGIN__;
934
935         window->useGl = false;
936
937         // Try double-buffered visual
938         glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
939         if (!glconfig)
940             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
941
942         // Set OpenGL-capability to the widget
943         if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))
944             CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
945
946         initGl();
947
948         window->useGl = true;
949
950         __END__;
951     }
952
953     void releaseGlContext(CvWindow* window)
954     {
955         //CV_FUNCNAME( "releaseGlContext" );
956
957         //__BEGIN__;
958
959         window->useGl = false;
960
961         //__END__;
962     }
963
964     void drawGl(CvWindow* window)
965     {
966         CV_FUNCNAME( "drawGl" );
967
968         __BEGIN__;
969
970         GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
971         GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
972
973         if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
974             CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
975
976         glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);
977
978         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
979
980         if (window->glDrawCallback)
981             window->glDrawCallback(window->glDrawData);
982
983         CV_CheckGlError();
984
985         if (gdk_gl_drawable_is_double_buffered (gldrawable))
986             gdk_gl_drawable_swap_buffers(gldrawable);
987         else
988             glFlush();
989
990         gdk_gl_drawable_gl_end(gldrawable);
991
992         __END__;
993     }
994 }
995
996 #endif // HAVE_OPENGL
997
998
999 static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
1000 {
1001 #ifdef HAVE_OPENGL
1002     CvWindow* window = (CvWindow*)data;
1003
1004     if (window->useGl)
1005     {
1006         drawGl(window);
1007         return TRUE;
1008     }
1009 #else
1010     (void)data;
1011 #endif
1012
1013   CvImageWidget *image_widget;
1014
1015   g_return_val_if_fail (widget != NULL, FALSE);
1016   g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
1017   g_return_val_if_fail (event != NULL, FALSE);
1018
1019   if (event->count > 0)
1020     return FALSE;
1021
1022   image_widget = CV_IMAGE_WIDGET (widget);
1023
1024   gdk_window_clear_area (widget->window,
1025                          0, 0,
1026                          widget->allocation.width,
1027                          widget->allocation.height);
1028   if( image_widget->scaled_image ){
1029       // center image in available region
1030       int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1031       int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1032
1033       gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
1034           x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
1035           MIN(image_widget->scaled_image->rows, widget->allocation.height),
1036           GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
1037   }
1038   else if( image_widget->original_image ){
1039       gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
1040           0, 0,
1041           MIN(image_widget->original_image->cols, widget->allocation.width),
1042            MIN(image_widget->original_image->rows, widget->allocation.height),
1043           GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
1044   }
1045   return TRUE;
1046 }
1047
1048 CV_IMPL int cvNamedWindow( const char* name, int flags )
1049 {
1050     int result = 0;
1051     CV_FUNCNAME( "cvNamedWindow" );
1052
1053     __BEGIN__;
1054
1055     CvWindow* window;
1056     int len;
1057
1058     cvInitSystem(1,(char**)&name);
1059     if( !name )
1060         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1061
1062     // Check the name in the storage
1063     if( icvFindWindowByName( name ) != 0 )
1064     {
1065         result = 1;
1066         EXIT;
1067     }
1068
1069     len = strlen(name);
1070     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
1071     memset( window, 0, sizeof(*window));
1072     window->name = (char*)(window + 1);
1073     memcpy( window->name, name, len + 1 );
1074     window->flags = flags;
1075     window->signature = CV_WINDOW_MAGIC_VAL;
1076     window->last_key = 0;
1077     window->on_mouse = 0;
1078     window->on_mouse_param = 0;
1079     memset( &window->toolbar, 0, sizeof(window->toolbar));
1080     window->next = hg_windows;
1081     window->prev = 0;
1082     window->status = CV_WINDOW_NORMAL;//YV
1083
1084     CV_LOCK_MUTEX();
1085
1086     window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
1087
1088     window->paned = gtk_vbox_new( FALSE, 0 );
1089     window->widget = cvImageWidgetNew( flags );
1090     gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
1091     gtk_widget_show( window->widget );
1092     gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
1093     gtk_widget_show( window->paned );
1094
1095 #ifndef HAVE_OPENGL
1096     if (flags & CV_WINDOW_OPENGL)
1097         CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
1098 #else
1099     if (flags & CV_WINDOW_OPENGL)
1100         createGlContext(window);
1101
1102     window->glDrawCallback = 0;
1103     window->glDrawData = 0;
1104
1105     window->glCleanCallback = 0;
1106     window->glCleanData = 0;
1107 #endif
1108
1109     //
1110     // configure event handlers
1111     // TODO -- move this to CvImageWidget ?
1112     gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event",
1113                         GTK_SIGNAL_FUNC(icvOnKeyPress), window );
1114     gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event",
1115                         GTK_SIGNAL_FUNC(icvOnMouse), window );
1116     gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event",
1117                         GTK_SIGNAL_FUNC(icvOnMouse), window );
1118     gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event",
1119                         GTK_SIGNAL_FUNC(icvOnMouse), window );
1120     gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event",
1121                         GTK_SIGNAL_FUNC(icvOnClose), window );
1122     gtk_signal_connect( GTK_OBJECT(window->widget), "expose-event",
1123                         GTK_SIGNAL_FUNC(cvImageWidget_expose), window );
1124
1125     gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
1126
1127     gtk_widget_show( window->frame );
1128     gtk_window_set_title( GTK_WINDOW(window->frame), name );
1129
1130     if( hg_windows )
1131         hg_windows->prev = window;
1132     hg_windows = window;
1133
1134     gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
1135
1136
1137     // allow window to be resized
1138     if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
1139         GdkGeometry geometry;
1140         geometry.min_width = 50;
1141         geometry.min_height = 50;
1142         gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
1143             &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
1144     }
1145
1146     CV_UNLOCK_MUTEX();
1147
1148 #ifdef HAVE_OPENGL
1149     if (window->useGl)
1150         cvSetOpenGlContext(name);
1151 #endif
1152
1153     result = 1;
1154     __END__;
1155
1156     return result;
1157 }
1158
1159
1160 #ifdef HAVE_OPENGL
1161
1162 CV_IMPL void cvSetOpenGlContext(const char* name)
1163 {
1164     CvWindow* window;
1165     GdkGLContext* glcontext;
1166     GdkGLDrawable* gldrawable;
1167
1168     CV_FUNCNAME( "cvSetOpenGlContext" );
1169
1170     __BEGIN__;
1171
1172     if(!name)
1173         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1174
1175     window = icvFindWindowByName( name );
1176     if (!window)
1177         CV_ERROR( CV_StsNullPtr, "NULL window" );
1178
1179     if (!window->useGl)
1180         CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
1181
1182     glcontext = gtk_widget_get_gl_context(window->widget);
1183     gldrawable = gtk_widget_get_gl_drawable(window->widget);
1184
1185     if (!gdk_gl_drawable_make_current(gldrawable, glcontext))
1186         CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
1187
1188     __END__;
1189 }
1190
1191 CV_IMPL void cvUpdateWindow(const char* name)
1192 {
1193     CV_FUNCNAME( "cvUpdateWindow" );
1194
1195     __BEGIN__;
1196
1197     CvWindow* window;
1198
1199     if (!name)
1200         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1201
1202     window = icvFindWindowByName( name );
1203     if (!window)
1204         EXIT;
1205
1206     // window does not refresh without this
1207     gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
1208
1209     __END__;
1210 }
1211
1212 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
1213 {
1214     CvWindow* window;
1215
1216     CV_FUNCNAME( "cvCreateOpenGLCallback" );
1217
1218     __BEGIN__;
1219
1220     if(!name)
1221         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1222
1223     window = icvFindWindowByName( name );
1224     if( !window )
1225         EXIT;
1226
1227     if (!window->useGl)
1228         CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
1229
1230     window->glDrawCallback = callback;
1231     window->glDrawData = userdata;
1232
1233     __END__;
1234 }
1235
1236 void icvSetOpenGlCleanCallback(const char* name, CvOpenGlCleanCallback callback, void* userdata)
1237 {
1238     CvWindow* window;
1239     GdkGLContext* glcontext;
1240     GdkGLDrawable* gldrawable;
1241
1242     CV_FUNCNAME( "icvSetOpenGlCleanCallback" );
1243
1244     __BEGIN__;
1245
1246     if (!name)
1247         CV_ERROR(CV_StsNullPtr, "NULL name string");
1248
1249     window = icvFindWindowByName(name);
1250     if (!window)
1251         EXIT;
1252
1253     if (!window->useGl)
1254         CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
1255
1256     glcontext = gtk_widget_get_gl_context(window->widget);
1257     gldrawable = gtk_widget_get_gl_drawable(window->widget);
1258
1259     gdk_gl_drawable_make_current(gldrawable, glcontext);
1260
1261     if (window->glCleanCallback)
1262         window->glCleanCallback(window->glCleanData);
1263
1264     window->glCleanCallback = callback;
1265     window->glCleanData = userdata;
1266
1267     __END__;
1268 }
1269
1270 #endif // HAVE_OPENGL
1271
1272
1273
1274
1275 static void icvDeleteWindow( CvWindow* window )
1276 {
1277     CvTrackbar* trackbar;
1278
1279 #ifdef HAVE_OPENGL
1280     if (window->useGl)
1281     {
1282         GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
1283         GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
1284
1285         gdk_gl_drawable_make_current(gldrawable, glcontext);
1286
1287         if (window->glCleanCallback)
1288         {
1289             window->glCleanCallback(window->glCleanData);
1290             window->glCleanCallback = 0;
1291             window->glCleanData = 0;
1292         }
1293
1294         releaseGlContext(window);
1295     }
1296 #endif
1297
1298     if( window->prev )
1299         window->prev->next = window->next;
1300     else
1301         hg_windows = window->next;
1302
1303     if( window->next )
1304         window->next->prev = window->prev;
1305
1306     window->prev = window->next = 0;
1307
1308     gtk_widget_destroy( window->frame );
1309
1310     for( trackbar = window->toolbar.first; trackbar != 0; )
1311     {
1312         CvTrackbar* next = trackbar->next;
1313         cvFree( &trackbar );
1314         trackbar = next;
1315     }
1316
1317     cvFree( &window );
1318 #ifdef HAVE_GTHREAD
1319     // if last window, send key press signal
1320     // to jump out of any waiting cvWaitKey's
1321     if(hg_windows==0 && thread_started){
1322         g_cond_broadcast(cond_have_key);
1323     }
1324 #endif
1325 }
1326
1327
1328 CV_IMPL void cvDestroyWindow( const char* name )
1329 {
1330     CV_FUNCNAME( "cvDestroyWindow" );
1331
1332     __BEGIN__;
1333
1334     CvWindow* window;
1335
1336     if(!name)
1337         CV_ERROR( CV_StsNullPtr, "NULL name string" );
1338
1339     window = icvFindWindowByName( name );
1340     if( !window )
1341         EXIT;
1342
1343     // note that it is possible for the update thread to run this function
1344     // if there is a call to cvShowImage in a mouse callback
1345     // (this would produce a deadlock on window_mutex)
1346     CV_LOCK_MUTEX();
1347
1348     icvDeleteWindow( window );
1349
1350     CV_UNLOCK_MUTEX();
1351
1352     __END__;
1353 }
1354
1355
1356 CV_IMPL void
1357 cvDestroyAllWindows( void )
1358 {
1359     CV_LOCK_MUTEX();
1360
1361     while( hg_windows )
1362     {
1363         CvWindow* window = hg_windows;
1364         icvDeleteWindow( window );
1365     }
1366     CV_UNLOCK_MUTEX();
1367 }
1368
1369 // CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
1370 //     CvSize window_size;
1371 //     GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
1372 //     gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
1373 //             &window_size.width, &window_size.height );
1374
1375 //     window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
1376 //     window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
1377
1378 //     return window_size;
1379 // }
1380
1381 CV_IMPL void
1382 cvShowImage( const char* name, const CvArr* arr )
1383 {
1384     CV_FUNCNAME( "cvShowImage" );
1385
1386     __BEGIN__;
1387
1388     CvWindow* window;
1389
1390     if( !name )
1391         CV_ERROR( CV_StsNullPtr, "NULL name" );
1392
1393     CV_LOCK_MUTEX();
1394
1395     window = icvFindWindowByName(name);
1396     if(!window)
1397     {
1398         cvNamedWindow(name, 1);
1399         window = icvFindWindowByName(name);
1400     }
1401
1402     if( window && arr )
1403     {
1404     #ifdef HAVE_OPENGL
1405         if (window->useGl)
1406         {
1407             CvMat stub;
1408             CvMat* mat = cvGetMat(arr, &stub);
1409             cv::Mat im(mat);
1410             cv::imshow(name, im);
1411             return;
1412         }
1413     #endif
1414
1415         CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
1416         cvImageWidgetSetImage( image_widget, arr );
1417     }
1418
1419     CV_UNLOCK_MUTEX();
1420
1421     __END__;
1422 }
1423
1424 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1425 {
1426     CV_FUNCNAME( "cvResizeWindow" );
1427
1428     __BEGIN__;
1429
1430     CvWindow* window;
1431     CvImageWidget * image_widget;
1432
1433     if( !name )
1434         CV_ERROR( CV_StsNullPtr, "NULL name" );
1435
1436     window = icvFindWindowByName(name);
1437     if(!window)
1438         EXIT;
1439
1440     image_widget = CV_IMAGE_WIDGET( window->widget );
1441     //if(image_widget->flags & CV_WINDOW_AUTOSIZE)
1442         //EXIT;
1443
1444     CV_LOCK_MUTEX();
1445
1446     gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
1447     gtk_window_resize( GTK_WINDOW(window->frame), width, height );
1448
1449     // disable initial resize since presumably user wants to keep
1450     // this window size
1451     image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
1452
1453     CV_UNLOCK_MUTEX();
1454
1455     __END__;
1456 }
1457
1458
1459 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1460 {
1461     CV_FUNCNAME( "cvMoveWindow" );
1462
1463     __BEGIN__;
1464
1465     CvWindow* window;
1466
1467     if( !name )
1468         CV_ERROR( CV_StsNullPtr, "NULL name" );
1469
1470     window = icvFindWindowByName(name);
1471     if(!window)
1472         EXIT;
1473
1474     CV_LOCK_MUTEX();
1475
1476     gtk_window_move( GTK_WINDOW(window->frame), x, y );
1477
1478     CV_UNLOCK_MUTEX();
1479
1480     __END__;
1481 }
1482
1483
1484 static CvTrackbar*
1485 icvFindTrackbarByName( const CvWindow* window, const char* name )
1486 {
1487     CvTrackbar* trackbar = window->toolbar.first;
1488
1489     for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1490         ;
1491
1492     return trackbar;
1493 }
1494
1495 static int
1496 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
1497                    int* val, int count, CvTrackbarCallback on_notify,
1498                    CvTrackbarCallback2 on_notify2, void* userdata )
1499 {
1500     int result = 0;
1501
1502     CV_FUNCNAME( "icvCreateTrackbar" );
1503
1504     __BEGIN__;
1505
1506     /*char slider_name[32];*/
1507     CvWindow* window = 0;
1508     CvTrackbar* trackbar = 0;
1509
1510     if( !window_name || !trackbar_name )
1511         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
1512
1513     if( count <= 0 )
1514         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
1515
1516     window = icvFindWindowByName(window_name);
1517     if( !window )
1518         EXIT;
1519
1520     trackbar = icvFindTrackbarByName(window,trackbar_name);
1521
1522     CV_LOCK_MUTEX();
1523
1524     if( !trackbar )
1525     {
1526         int len = strlen(trackbar_name);
1527         trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
1528         memset( trackbar, 0, sizeof(*trackbar));
1529         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
1530         trackbar->name = (char*)(trackbar+1);
1531         memcpy( trackbar->name, trackbar_name, len + 1 );
1532         trackbar->parent = window;
1533         trackbar->next = window->toolbar.first;
1534         window->toolbar.first = trackbar;
1535
1536         GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
1537         GtkWidget* hscale_label = gtk_label_new( trackbar_name );
1538         GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
1539         gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS );
1540         gtk_scale_set_digits( GTK_SCALE(hscale), 0 );
1541         //gtk_scale_set_value_pos( hscale, GTK_POS_TOP );
1542         gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );
1543
1544         trackbar->widget = hscale;
1545         gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );
1546         gtk_widget_show( hscale_label );
1547         gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );
1548         gtk_widget_show( hscale );
1549         gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );
1550         gtk_widget_show( hscale_box );
1551
1552     }
1553
1554     if( val )
1555     {
1556         int value = *val;
1557         if( value < 0 )
1558             value = 0;
1559         if( value > count )
1560             value = count;
1561         gtk_range_set_value( GTK_RANGE(trackbar->widget), value );
1562         trackbar->pos = value;
1563         trackbar->data = val;
1564     }
1565
1566     trackbar->maxval = count;
1567     trackbar->notify = on_notify;
1568     trackbar->notify2 = on_notify2;
1569     trackbar->userdata = userdata;
1570     gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed",
1571                         GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar );
1572
1573     // queue a widget resize to trigger a window resize to
1574     // compensate for the addition of trackbars
1575     gtk_widget_queue_resize( GTK_WIDGET(window->widget) );
1576
1577
1578     CV_UNLOCK_MUTEX();
1579
1580     result = 1;
1581
1582     __END__;
1583
1584     return result;
1585 }
1586
1587
1588 CV_IMPL int
1589 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1590                   int* val, int count, CvTrackbarCallback on_notify )
1591 {
1592     return icvCreateTrackbar(trackbar_name, window_name, val, count,
1593                              on_notify, 0, 0);
1594 }
1595
1596
1597 CV_IMPL int
1598 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
1599                    int* val, int count, CvTrackbarCallback2 on_notify2,
1600                    void* userdata )
1601 {
1602     return icvCreateTrackbar(trackbar_name, window_name, val, count,
1603                              0, on_notify2, userdata);
1604 }
1605
1606
1607 CV_IMPL void
1608 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1609 {
1610     CV_FUNCNAME( "cvSetMouseCallback" );
1611
1612     __BEGIN__;
1613
1614     CvWindow* window = 0;
1615
1616     if( !window_name )
1617         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1618
1619     window = icvFindWindowByName(window_name);
1620     if( !window )
1621         EXIT;
1622
1623     window->on_mouse = on_mouse;
1624     window->on_mouse_param = param;
1625
1626     __END__;
1627 }
1628
1629
1630 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1631 {
1632     int pos = -1;
1633
1634     CV_FUNCNAME( "cvGetTrackbarPos" );
1635
1636     __BEGIN__;
1637
1638     CvWindow* window;
1639     CvTrackbar* trackbar = 0;
1640
1641     if( trackbar_name == 0 || window_name == 0 )
1642         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1643
1644     window = icvFindWindowByName( window_name );
1645     if( window )
1646         trackbar = icvFindTrackbarByName( window, trackbar_name );
1647
1648     if( trackbar )
1649         pos = trackbar->pos;
1650
1651     __END__;
1652
1653     return pos;
1654 }
1655
1656
1657 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1658 {
1659     CV_FUNCNAME( "cvSetTrackbarPos" );
1660
1661     __BEGIN__;
1662
1663     CvWindow* window;
1664     CvTrackbar* trackbar = 0;
1665
1666     if( trackbar_name == 0 || window_name == 0 )
1667         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1668
1669     window = icvFindWindowByName( window_name );
1670     if( window )
1671         trackbar = icvFindTrackbarByName( window, trackbar_name );
1672
1673     if( trackbar )
1674     {
1675         if( pos < 0 )
1676             pos = 0;
1677
1678         if( pos > trackbar->maxval )
1679             pos = trackbar->maxval;
1680     }
1681
1682     CV_LOCK_MUTEX();
1683
1684     gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
1685
1686     CV_UNLOCK_MUTEX();
1687
1688     __END__;
1689 }
1690
1691
1692 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1693 {
1694     void* widget = 0;
1695
1696     CV_FUNCNAME( "cvGetWindowHandle" );
1697
1698     __BEGIN__;
1699
1700     CvWindow* window;
1701
1702     if( window_name == 0 )
1703         CV_ERROR( CV_StsNullPtr, "NULL window name" );
1704
1705     window = icvFindWindowByName( window_name );
1706     if( window )
1707         widget = (void*)window->widget;
1708
1709     __END__;
1710
1711     return widget;
1712 }
1713
1714
1715 CV_IMPL const char* cvGetWindowName( void* window_handle )
1716 {
1717     const char* window_name = "";
1718
1719     CV_FUNCNAME( "cvGetWindowName" );
1720
1721     __BEGIN__;
1722
1723     CvWindow* window;
1724
1725     if( window_handle == 0 )
1726         CV_ERROR( CV_StsNullPtr, "NULL window" );
1727
1728     window = icvWindowByWidget( (GtkWidget*)window_handle );
1729     if( window )
1730         window_name = window->name;
1731
1732     __END__;
1733
1734     return window_name;
1735 }
1736
1737 static gboolean icvOnKeyPress( GtkWidget * /*widget*/,
1738                 GdkEventKey* event, gpointer /*user_data*/ )
1739 {
1740     int code = 0;
1741
1742     switch( event->keyval )
1743     {
1744     case GDK_Escape:
1745         code = 27;
1746         break;
1747     case GDK_Return:
1748     case GDK_Linefeed:
1749         code = '\n';
1750         break;
1751     case GDK_Tab:
1752         code = '\t';
1753     break;
1754     default:
1755         code = event->keyval;
1756     }
1757
1758     code |= event->state << 16;
1759
1760 #ifdef HAVE_GTHREAD
1761     if(thread_started) g_mutex_lock(last_key_mutex);
1762 #endif
1763
1764     last_key = code;
1765
1766 #ifdef HAVE_GTHREAD
1767     if(thread_started){
1768         // signal any waiting threads
1769         g_cond_broadcast(cond_have_key);
1770         g_mutex_unlock(last_key_mutex);
1771     }
1772 #endif
1773
1774     return FALSE;
1775 }
1776
1777
1778 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
1779 {
1780     int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
1781     CvTrackbar* trackbar = (CvTrackbar*)user_data;
1782
1783     if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
1784         trackbar->widget == widget )
1785     {
1786         trackbar->pos = pos;
1787         if( trackbar->data )
1788             *trackbar->data = pos;
1789         if( trackbar->notify2 )
1790             trackbar->notify2(pos, trackbar->userdata);
1791         else if( trackbar->notify )
1792             trackbar->notify(pos);
1793     }
1794 }
1795
1796 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
1797 {
1798     CvWindow* window = (CvWindow*)user_data;
1799     if( window->signature == CV_WINDOW_MAGIC_VAL &&
1800         window->frame == widget )
1801     {
1802         icvDeleteWindow(window);
1803     }
1804     return TRUE;
1805 }
1806
1807
1808 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
1809 {
1810     // TODO move this logic to CvImageWidget
1811     CvWindow* window = (CvWindow*)user_data;
1812     CvPoint2D32f pt32f = {-1., -1.};
1813     CvPoint pt = {-1,-1};
1814     int cv_event = -1, state = 0;
1815     CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
1816
1817     if( window->signature != CV_WINDOW_MAGIC_VAL ||
1818         window->widget != widget || !window->widget ||
1819         !window->on_mouse /*|| !image_widget->original_image*/)
1820         return FALSE;
1821
1822     if( event->type == GDK_MOTION_NOTIFY )
1823     {
1824         GdkEventMotion* event_motion = (GdkEventMotion*)event;
1825
1826         cv_event = CV_EVENT_MOUSEMOVE;
1827         pt32f.x = cvRound(event_motion->x);
1828         pt32f.y = cvRound(event_motion->y);
1829         state = event_motion->state;
1830     }
1831     else if( event->type == GDK_BUTTON_PRESS ||
1832              event->type == GDK_BUTTON_RELEASE ||
1833              event->type == GDK_2BUTTON_PRESS )
1834     {
1835         GdkEventButton* event_button = (GdkEventButton*)event;
1836         pt32f.x = cvRound(event_button->x);
1837         pt32f.y = cvRound(event_button->y);
1838
1839
1840         if( event_button->type == GDK_BUTTON_PRESS )
1841         {
1842             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
1843                        event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
1844                        event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
1845         }
1846         else if( event_button->type == GDK_BUTTON_RELEASE )
1847         {
1848             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
1849                        event_button->button == 2 ? CV_EVENT_MBUTTONUP :
1850                        event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
1851         }
1852         else if( event_button->type == GDK_2BUTTON_PRESS )
1853         {
1854             cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
1855                        event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
1856                        event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
1857         }
1858         state = event_button->state;
1859     }
1860
1861     if( cv_event >= 0 ){
1862         // scale point if image is scaled
1863         if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
1864              image_widget->original_image &&
1865              image_widget->scaled_image ){
1866             // image origin is not necessarily at (0,0)
1867             int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1868             int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1869             pt.x = cvRound( ((pt32f.x-x0)*image_widget->original_image->cols)/
1870                                             image_widget->scaled_image->cols );
1871             pt.y = cvRound( ((pt32f.y-y0)*image_widget->original_image->rows)/
1872                                             image_widget->scaled_image->rows );
1873         }
1874         else{
1875             pt = cvPointFrom32f( pt32f );
1876         }
1877
1878 //        if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
1879 //           (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
1880         {
1881             int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
1882                 (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
1883                 (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
1884                 (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
1885                 (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
1886                 (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
1887             window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
1888         }
1889     }
1890
1891         return FALSE;
1892     }
1893
1894
1895 static gboolean icvAlarm( gpointer user_data )
1896 {
1897     *(int*)user_data = 1;
1898     return FALSE;
1899 }
1900
1901
1902 CV_IMPL int cvWaitKey( int delay )
1903 {
1904 #ifdef HAVE_GTHREAD
1905     if(thread_started && g_thread_self()!=window_thread){
1906         gboolean expired;
1907         int my_last_key;
1908
1909         // wait for signal or timeout if delay > 0
1910         if(delay>0){
1911             GTimeVal timer;
1912             g_get_current_time(&timer);
1913             g_time_val_add(&timer, delay*1000);
1914             expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
1915         }
1916         else{
1917             g_cond_wait(cond_have_key, last_key_mutex);
1918             expired=false;
1919         }
1920         my_last_key = last_key;
1921         g_mutex_unlock(last_key_mutex);
1922         if(expired || hg_windows==0){
1923             return -1;
1924         }
1925         return my_last_key;
1926     }
1927     else{
1928 #endif
1929         int expired = 0;
1930         guint timer = 0;
1931         if( delay > 0 )
1932             timer = g_timeout_add( delay, icvAlarm, &expired );
1933         last_key = -1;
1934         while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 )
1935             ;
1936
1937         if( delay > 0 && !expired )
1938             g_source_remove(timer);
1939 #ifdef HAVE_GTHREAD
1940     }
1941 #endif
1942     return last_key;
1943 }
1944
1945
1946 #endif  // HAVE_GTK
1947 #endif  // WIN32
1948
1949 /* End of file. */