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