1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
49 #include "gdk/gdkkeysyms.h"
53 /*#if _MSC_VER >= 1200
54 #pragma warning( disable: 4505 )
55 #pragma comment(lib,"gtk-win32-2.0.lib")
56 #pragma comment(lib,"glib-2.0.lib")
57 #pragma comment(lib,"gobject-2.0.lib")
58 #pragma comment(lib,"gdk-win32-2.0.lib")
59 #pragma comment(lib,"gdk_pixbuf-2.0.lib")
63 // TODO Fix the initial window size when flags=0. Right now the initial window is by default
64 // 320x240 size. A better default would be actual size of the image. Problem
65 // is determining desired window size with trackbars while still allowing resizing.
67 // Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio
68 // in totem/src/backend/bacon-video-widget-xine.c
70 ////////////////////////////////////////////////////////////
71 // CvImageWidget GTK Widget Public API
72 ////////////////////////////////////////////////////////////
73 typedef struct _CvImageWidget CvImageWidget;
74 typedef struct _CvImageWidgetClass CvImageWidgetClass;
76 struct _CvImageWidget {
78 CvMat * original_image;
83 struct _CvImageWidgetClass
85 GtkWidgetClass parent_class;
89 /** Allocate new image viewer widget */
90 GtkWidget* cvImageWidgetNew (int flags);
92 /** Set the image to display in the widget */
93 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr);
95 // standard GTK object macros
96 #define CV_IMAGE_WIDGET(obj) GTK_CHECK_CAST (obj, cvImageWidget_get_type (), CvImageWidget)
97 #define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass)
98 #define CV_IS_IMAGE_WIDGET(obj) GTK_CHECK_TYPE (obj, cvImageWidget_get_type ())
100 /////////////////////////////////////////////////////////////////////////////
101 // Private API ////////////////////////////////////////////////////////
102 /////////////////////////////////////////////////////////////////////////////
103 GtkType cvImageWidget_get_type (void);
105 static GtkWidgetClass * parent_class = NULL;
107 // flag to help size initial window
108 #define CV_WINDOW_NO_IMAGE 2
110 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){
114 //printf("cvImageWidgetSetImage\n");
116 if( CV_IS_IMAGE_HDR( arr ))
117 origin = ((IplImage*)arr)->origin;
119 mat = cvGetMat(arr, &stub);
121 if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){
122 cvReleaseMat( &widget->original_image );
124 if(!widget->original_image){
125 widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 );
126 gtk_widget_queue_resize( GTK_WIDGET( widget ) );
128 cvConvertImage( mat, widget->original_image,
129 (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
130 if(widget->scaled_image){
131 cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA );
134 // window does not refresh without this
135 gtk_widget_queue_draw( GTK_WIDGET(widget) );
139 cvImageWidgetNew (int flags)
141 CvImageWidget *image_widget;
143 image_widget = CV_IMAGE_WIDGET( gtk_type_new (cvImageWidget_get_type ()) );
144 image_widget->original_image = 0;
145 image_widget->scaled_image = 0;
146 image_widget->flags = flags | CV_WINDOW_NO_IMAGE;
148 return GTK_WIDGET (image_widget);
152 cvImageWidget_realize (GtkWidget *widget)
154 CvImageWidget *image_widget;
155 GdkWindowAttr attributes;
156 gint attributes_mask;
158 //printf("cvImageWidget_realize\n");
159 g_return_if_fail (widget != NULL);
160 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
162 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
163 image_widget = CV_IMAGE_WIDGET (widget);
165 attributes.x = widget->allocation.x;
166 attributes.y = widget->allocation.y;
167 attributes.width = widget->allocation.width;
168 attributes.height = widget->allocation.height;
169 attributes.wclass = GDK_INPUT_OUTPUT;
170 attributes.window_type = GDK_WINDOW_CHILD;
171 attributes.event_mask = gtk_widget_get_events (widget) |
172 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
173 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
174 attributes.visual = gtk_widget_get_visual (widget);
175 attributes.colormap = gtk_widget_get_colormap (widget);
177 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
178 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
180 widget->style = gtk_style_attach (widget->style, widget->window);
182 gdk_window_set_user_data (widget->window, widget);
184 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
187 static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){
188 float aspect = (float)im_width/(float)im_height;
189 float max_aspect = (float)max_width/(float)max_height;
190 if(aspect > max_aspect){
191 return cvSize( max_width, cvRound(max_width/aspect) );
193 return cvSize( cvRound(max_height*aspect), max_height );
197 cvImageWidget_size_request (GtkWidget *widget,
198 GtkRequisition *requisition)
200 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
202 //printf("cvImageWidget_size_request ");
203 // the case the first time cvShowImage called or when AUTOSIZE
204 if( image_widget->original_image &&
205 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
206 (image_widget->flags & CV_WINDOW_NO_IMAGE)))
208 //printf("original ");
209 requisition->width = image_widget->original_image->cols;
210 requisition->height = image_widget->original_image->rows;
213 else if(image_widget->scaled_image){
215 requisition->width = image_widget->scaled_image->cols;
216 requisition->height = image_widget->scaled_image->rows;
218 // the case before cvShowImage called
220 //printf("default ");
221 requisition->width = 320;
222 requisition->height = 240;
224 //printf("%d %d\n",requisition->width, requisition->height);
227 static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){
228 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
230 //printf("cvImageWidget_set_size %d %d\n", max_width, max_height);
232 // don't allow to set the size
233 if(image_widget->flags & CV_WINDOW_AUTOSIZE) return;
234 if(!image_widget->original_image) return;
236 CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols,
237 image_widget->original_image->rows, max_width, max_height );
239 if( image_widget->scaled_image &&
240 ( image_widget->scaled_image->cols != scaled_image_size.width ||
241 image_widget->scaled_image->rows != scaled_image_size.height ))
243 cvReleaseMat( &image_widget->scaled_image );
245 if( !image_widget->scaled_image ){
246 image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 );
250 assert( image_widget->scaled_image );
254 cvImageWidget_size_allocate (GtkWidget *widget,
255 GtkAllocation *allocation)
257 CvImageWidget *image_widget;
259 //printf("cvImageWidget_size_allocate\n");
260 g_return_if_fail (widget != NULL);
261 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
262 g_return_if_fail (allocation != NULL);
264 widget->allocation = *allocation;
265 image_widget = CV_IMAGE_WIDGET (widget);
268 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){
269 // (re) allocated scaled image
270 if( image_widget->flags & CV_WINDOW_NO_IMAGE ){
271 cvImageWidget_set_size( widget, image_widget->original_image->cols,
272 image_widget->original_image->rows);
275 cvImageWidget_set_size( widget, allocation->width, allocation->height );
277 cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA );
280 if (GTK_WIDGET_REALIZED (widget))
282 image_widget = CV_IMAGE_WIDGET (widget);
284 if( image_widget->original_image &&
285 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
286 (image_widget->flags & CV_WINDOW_NO_IMAGE)) )
288 widget->allocation.width = image_widget->original_image->cols;
289 widget->allocation.height = image_widget->original_image->rows;
290 gdk_window_move_resize( widget->window, allocation->x, allocation->y,
291 image_widget->original_image->cols, image_widget->original_image->rows );
292 if(image_widget->flags & CV_WINDOW_NO_IMAGE){
293 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
294 gtk_widget_queue_resize( GTK_WIDGET(widget) );
298 gdk_window_move_resize (widget->window,
299 allocation->x, allocation->y,
300 allocation->width, allocation->height );
307 cvImageWidget_expose( GtkWidget *widget,
308 GdkEventExpose *event )
310 CvImageWidget *image_widget;
312 g_return_val_if_fail (widget != NULL, FALSE);
313 g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
314 g_return_val_if_fail (event != NULL, FALSE);
316 if (event->count > 0)
319 image_widget = CV_IMAGE_WIDGET (widget);
321 gdk_window_clear_area (widget->window,
323 widget->allocation.width,
324 widget->allocation.height);
325 if( image_widget->scaled_image ){
326 // center image in available region
327 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
328 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
330 gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
331 x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
332 MIN(image_widget->scaled_image->rows, widget->allocation.height),
333 GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
335 else if( image_widget->original_image ){
336 gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
338 MIN(image_widget->original_image->cols, widget->allocation.width),
339 MIN(image_widget->original_image->rows, widget->allocation.height),
340 GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
346 cvImageWidget_destroy (GtkObject *object)
348 CvImageWidget *image_widget;
350 g_return_if_fail (object != NULL);
351 g_return_if_fail (CV_IS_IMAGE_WIDGET (object));
353 image_widget = CV_IMAGE_WIDGET (object);
355 cvReleaseMat( &image_widget->scaled_image );
356 cvReleaseMat( &image_widget->original_image );
358 if (GTK_OBJECT_CLASS (parent_class)->destroy)
359 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
362 static void cvImageWidget_class_init (CvImageWidgetClass * klass)
364 GtkObjectClass *object_class;
365 GtkWidgetClass *widget_class;
367 object_class = (GtkObjectClass*) klass;
368 widget_class = (GtkWidgetClass*) klass;
370 parent_class = GTK_WIDGET_CLASS( gtk_type_class (gtk_widget_get_type ()) );
372 object_class->destroy = cvImageWidget_destroy;
374 widget_class->realize = cvImageWidget_realize;
375 widget_class->expose_event = cvImageWidget_expose;
376 widget_class->size_request = cvImageWidget_size_request;
377 widget_class->size_allocate = cvImageWidget_size_allocate;
378 widget_class->button_press_event = NULL;
379 widget_class->button_release_event = NULL;
380 widget_class->motion_notify_event = NULL;
384 cvImageWidget_init (CvImageWidget *image_widget)
386 image_widget->original_image=0;
387 image_widget->scaled_image=0;
388 image_widget->flags=0;
391 GtkType cvImageWidget_get_type (void){
392 static GtkType image_type = 0;
396 static const GtkTypeInfo image_info =
398 (gchar*)"CvImageWidget",
399 sizeof (CvImageWidget),
400 sizeof (CvImageWidgetClass),
401 (GtkClassInitFunc) cvImageWidget_class_init,
402 (GtkObjectInitFunc) cvImageWidget_init,
403 /* reserved_1 */ NULL,
404 /* reserved_1 */ NULL,
405 (GtkClassInitFunc) NULL
408 image_type = gtk_type_unique (GTK_TYPE_WIDGET, &image_info);
413 /////////////////////////////////////////////////////////////////////////////
415 /////////////////////////////////////////////////////////////////////////////
420 typedef struct CvTrackbar
430 CvTrackbarCallback notify;
431 CvTrackbarCallback2 notify2;
436 typedef struct CvWindow
449 CvMouseCallback on_mouse;
450 void* on_mouse_param;
463 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
464 static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
465 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
466 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
469 int thread_started=0;
470 static gpointer icvWindowThreadLoop();
471 GMutex* last_key_mutex;
472 GCond* cond_have_key;
473 GMutex* window_mutex;
474 GThread* window_thread;
475 GtkWidget* cvTopLevelWidget = 0;
478 static int last_key = -1;
479 static CvWindow* hg_windows = 0;
481 CV_IMPL int cvInitSystem( int argc, char** argv )
483 static int wasInitialized = 0;
485 // check initialization status
486 if( !wasInitialized )
490 gtk_init( &argc, &argv );
497 CV_IMPL int cvStartWindowThread(){
499 cvInitSystem(0,NULL);
500 if (!thread_started) {
501 if (!g_thread_supported ()) {
502 /* the GThread system wasn't inited, so init it */
506 // this mutex protects the window resources
507 window_mutex = g_mutex_new();
509 // protects the 'last key pressed' variable
510 last_key_mutex = g_mutex_new();
512 // conditional that indicates a key has been pressed
513 cond_have_key = g_cond_new();
515 // this is the window update thread
516 window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
519 thread_started = window_thread!=NULL;
520 return thread_started;
527 gpointer icvWindowThreadLoop(){
529 g_mutex_lock(window_mutex);
530 gtk_main_iteration_do(FALSE);
531 g_mutex_unlock(window_mutex);
541 #define CV_LOCK_MUTEX() \
542 if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { }
544 #define CV_UNLOCK_MUTEX() \
545 if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { }
548 #define CV_LOCK_MUTEX()
549 #define CV_UNLOCK_MUTEX()
552 static CvWindow* icvFindWindowByName( const char* name )
554 CvWindow* window = hg_windows;
555 while( window != 0 && strcmp(name, window->name) != 0 )
556 window = window->next;
561 static CvWindow* icvWindowByWidget( GtkWidget* widget )
563 CvWindow* window = hg_windows;
565 while( window != 0 && window->widget != widget &&
566 window->frame != widget && window->paned != widget )
567 window = window->next;
572 CV_IMPL int cvNamedWindow( const char* name, int flags )
575 CV_FUNCNAME( "cvNamedWindow" );
582 cvInitSystem(1,(char**)&name);
584 CV_ERROR( CV_StsNullPtr, "NULL name string" );
586 // Check the name in the storage
587 if( icvFindWindowByName( name ) != 0 )
594 CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
595 memset( window, 0, sizeof(*window));
596 window->name = (char*)(window + 1);
597 memcpy( window->name, name, len + 1 );
598 window->flags = flags;
599 window->signature = CV_WINDOW_MAGIC_VAL;
600 window->last_key = 0;
601 window->on_mouse = 0;
602 window->on_mouse_param = 0;
603 memset( &window->toolbar, 0, sizeof(window->toolbar));
604 window->next = hg_windows;
609 window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
611 window->paned = gtk_vbox_new( FALSE, 0 );
612 window->widget = cvImageWidgetNew( flags );
613 gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
614 gtk_widget_show( window->widget );
615 gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
616 gtk_widget_show( window->paned );
618 // configure event handlers
619 // TODO -- move this to CvImageWidget ?
620 gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event",
621 GTK_SIGNAL_FUNC(icvOnKeyPress), window );
622 gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event",
623 GTK_SIGNAL_FUNC(icvOnMouse), window );
624 gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event",
625 GTK_SIGNAL_FUNC(icvOnMouse), window );
626 gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event",
627 GTK_SIGNAL_FUNC(icvOnMouse), window );
628 gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event",
629 GTK_SIGNAL_FUNC(icvOnClose), window );
631 gtk_widget_add_events (window->widget, GDK_EXPOSURE_MASK | GDK_BUTTON_RELEASE_MASK |
632 GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
634 gtk_widget_show( window->frame );
635 gtk_window_set_title( GTK_WINDOW(window->frame), name );
638 hg_windows->prev = window;
641 gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
644 // allow window to be resized
645 if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
646 GdkGeometry geometry;
647 geometry.min_width = 50;
648 geometry.min_height = 50;
649 gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
650 &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
662 static void icvDeleteWindow( CvWindow* window )
664 CvTrackbar* trackbar;
667 window->prev->next = window->next;
669 hg_windows = window->next;
672 window->next->prev = window->prev;
674 window->prev = window->next = 0;
676 gtk_widget_destroy( window->frame );
678 for( trackbar = window->toolbar.first; trackbar != 0; )
680 CvTrackbar* next = trackbar->next;
687 // if last window, send key press signal
688 // to jump out of any waiting cvWaitKey's
689 if(hg_windows==0 && thread_started){
690 g_cond_broadcast(cond_have_key);
696 CV_IMPL void cvDestroyWindow( const char* name )
698 CV_FUNCNAME( "cvDestroyWindow" );
705 CV_ERROR( CV_StsNullPtr, "NULL name string" );
707 window = icvFindWindowByName( name );
711 // note that it is possible for the update thread to run this function
712 // if there is a call to cvShowImage in a mouse callback
713 // (this would produce a deadlock on window_mutex)
716 icvDeleteWindow( window );
725 cvDestroyAllWindows( void )
731 CvWindow* window = hg_windows;
732 icvDeleteWindow( window );
737 CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
739 GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
740 gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
741 &window_size.width, &window_size.height );
743 window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
744 window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
750 cvShowImage( const char* name, const CvArr* arr )
752 CV_FUNCNAME( "cvShowImage" );
759 CV_ERROR( CV_StsNullPtr, "NULL name" );
763 window = icvFindWindowByName(name);
766 cvNamedWindow(name, 1);
767 window = icvFindWindowByName(name);
770 CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
771 cvImageWidgetSetImage( image_widget, arr );
779 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
781 CV_FUNCNAME( "cvResizeWindow" );
786 CvImageWidget * image_widget;
789 CV_ERROR( CV_StsNullPtr, "NULL name" );
791 window = icvFindWindowByName(name);
795 image_widget = CV_IMAGE_WIDGET( window->widget );
796 if(image_widget->flags & CV_WINDOW_AUTOSIZE)
801 gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
802 gtk_window_resize( GTK_WINDOW(window->frame), width, height );
804 // disable initial resize since presumably user wants to keep
806 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
814 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
816 CV_FUNCNAME( "cvMoveWindow" );
823 CV_ERROR( CV_StsNullPtr, "NULL name" );
825 window = icvFindWindowByName(name);
831 gtk_window_move( GTK_WINDOW(window->frame), x, y );
840 icvFindTrackbarByName( const CvWindow* window, const char* name )
842 CvTrackbar* trackbar = window->toolbar.first;
844 for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
851 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
852 int* val, int count, CvTrackbarCallback on_notify,
853 CvTrackbarCallback2 on_notify2, void* userdata )
857 CV_FUNCNAME( "icvCreateTrackbar" );
861 /*char slider_name[32];*/
862 CvWindow* window = 0;
863 CvTrackbar* trackbar = 0;
865 if( !window_name || !trackbar_name )
866 CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
869 CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
871 window = icvFindWindowByName(window_name);
875 trackbar = icvFindTrackbarByName(window,trackbar_name);
881 int len = strlen(trackbar_name);
882 trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
883 memset( trackbar, 0, sizeof(*trackbar));
884 trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
885 trackbar->name = (char*)(trackbar+1);
886 memcpy( trackbar->name, trackbar_name, len + 1 );
887 trackbar->parent = window;
888 trackbar->next = window->toolbar.first;
889 window->toolbar.first = trackbar;
891 GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
892 GtkWidget* hscale_label = gtk_label_new( trackbar_name );
893 GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
894 gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS );
895 gtk_scale_set_digits( GTK_SCALE(hscale), 0 );
896 //gtk_scale_set_value_pos( hscale, GTK_POS_TOP );
897 gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );
899 trackbar->widget = hscale;
900 gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );
901 gtk_widget_show( hscale_label );
902 gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );
903 gtk_widget_show( hscale );
904 gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );
905 gtk_widget_show( hscale_box );
916 gtk_range_set_value( GTK_RANGE(trackbar->widget), value );
917 trackbar->pos = value;
918 trackbar->data = val;
921 trackbar->maxval = count;
922 trackbar->notify = on_notify;
923 trackbar->notify2 = on_notify2;
924 trackbar->userdata = userdata;
925 gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed",
926 GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar );
928 // queue a widget resize to trigger a window resize to
929 // compensate for the addition of trackbars
930 gtk_widget_queue_resize( GTK_WIDGET(window->widget) );
944 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
945 int* val, int count, CvTrackbarCallback on_notify )
947 return icvCreateTrackbar(trackbar_name, window_name, val, count,
953 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
954 int* val, int count, CvTrackbarCallback2 on_notify2,
957 return icvCreateTrackbar(trackbar_name, window_name, val, count,
958 0, on_notify2, userdata);
963 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
965 CV_FUNCNAME( "cvSetMouseCallback" );
969 CvWindow* window = 0;
972 CV_ERROR( CV_StsNullPtr, "NULL window name" );
974 window = icvFindWindowByName(window_name);
978 window->on_mouse = on_mouse;
979 window->on_mouse_param = param;
985 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
989 CV_FUNCNAME( "cvGetTrackbarPos" );
994 CvTrackbar* trackbar = 0;
996 if( trackbar_name == 0 || window_name == 0 )
997 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
999 window = icvFindWindowByName( window_name );
1001 trackbar = icvFindTrackbarByName( window, trackbar_name );
1004 pos = trackbar->pos;
1012 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1014 CV_FUNCNAME( "cvSetTrackbarPos" );
1019 CvTrackbar* trackbar = 0;
1021 if( trackbar_name == 0 || window_name == 0 )
1022 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1024 window = icvFindWindowByName( window_name );
1026 trackbar = icvFindTrackbarByName( window, trackbar_name );
1033 if( pos > trackbar->maxval )
1034 pos = trackbar->maxval;
1039 gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
1047 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1051 CV_FUNCNAME( "cvGetWindowHandle" );
1057 if( window_name == 0 )
1058 CV_ERROR( CV_StsNullPtr, "NULL window name" );
1060 window = icvFindWindowByName( window_name );
1062 widget = (void*)window->widget;
1070 CV_IMPL const char* cvGetWindowName( void* window_handle )
1072 const char* window_name = "";
1074 CV_FUNCNAME( "cvGetWindowName" );
1080 if( window_handle == 0 )
1081 CV_ERROR( CV_StsNullPtr, "NULL window" );
1083 window = icvWindowByWidget( (GtkWidget*)window_handle );
1085 window_name = window->name;
1092 static gboolean icvOnKeyPress( GtkWidget * /*widget*/,
1093 GdkEventKey* event, gpointer /*user_data*/ )
1097 switch( event->keyval )
1110 code = event->keyval;
1113 code |= event->state << 16;
1116 if(thread_started) g_mutex_lock(last_key_mutex);
1123 // signal any waiting threads
1124 g_cond_broadcast(cond_have_key);
1125 g_mutex_unlock(last_key_mutex);
1133 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
1135 int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
1136 CvTrackbar* trackbar = (CvTrackbar*)user_data;
1138 if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
1139 trackbar->widget == widget )
1141 trackbar->pos = pos;
1142 if( trackbar->data )
1143 *trackbar->data = pos;
1144 if( trackbar->notify2 )
1145 trackbar->notify2(pos, trackbar->userdata);
1146 else if( trackbar->notify )
1147 trackbar->notify(pos);
1151 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
1153 CvWindow* window = (CvWindow*)user_data;
1154 if( window->signature == CV_WINDOW_MAGIC_VAL &&
1155 window->frame == widget )
1157 icvDeleteWindow(window);
1163 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
1165 // TODO move this logic to CvImageWidget
1166 CvWindow* window = (CvWindow*)user_data;
1167 CvPoint2D32f pt32f = {-1., -1.};
1168 CvPoint pt = {-1,-1};
1169 int cv_event = -1, state = 0;
1170 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
1172 if( window->signature != CV_WINDOW_MAGIC_VAL ||
1173 window->widget != widget || !window->widget ||
1174 !window->on_mouse || !image_widget->original_image)
1177 if( event->type == GDK_MOTION_NOTIFY )
1179 GdkEventMotion* event_motion = (GdkEventMotion*)event;
1181 cv_event = CV_EVENT_MOUSEMOVE;
1182 pt32f.x = cvRound(event_motion->x);
1183 pt32f.y = cvRound(event_motion->y);
1184 state = event_motion->state;
1186 else if( event->type == GDK_BUTTON_PRESS ||
1187 event->type == GDK_BUTTON_RELEASE ||
1188 event->type == GDK_2BUTTON_PRESS )
1190 GdkEventButton* event_button = (GdkEventButton*)event;
1191 pt32f.x = cvRound(event_button->x);
1192 pt32f.y = cvRound(event_button->y);
1195 if( event_button->type == GDK_BUTTON_PRESS )
1197 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
1198 event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
1199 event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
1201 else if( event_button->type == GDK_BUTTON_RELEASE )
1203 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
1204 event_button->button == 2 ? CV_EVENT_MBUTTONUP :
1205 event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
1207 else if( event_button->type == GDK_2BUTTON_PRESS )
1209 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
1210 event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
1211 event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
1213 state = event_button->state;
1216 if( cv_event >= 0 ){
1217 // scale point if image is scaled
1218 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
1219 image_widget->original_image &&
1220 image_widget->scaled_image ){
1221 // image origin is not necessarily at (0,0)
1222 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1223 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1224 pt.x = cvRound( ((pt32f.x-x0)*image_widget->original_image->cols)/
1225 image_widget->scaled_image->cols );
1226 pt.y = cvRound( ((pt32f.y-y0)*image_widget->original_image->rows)/
1227 image_widget->scaled_image->rows );
1230 pt = cvPointFrom32f( pt32f );
1233 if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
1234 (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
1236 int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
1237 (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
1238 (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
1239 (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
1240 (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
1241 (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
1242 window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
1250 static gboolean icvAlarm( gpointer user_data )
1252 *(int*)user_data = 1;
1257 CV_IMPL int cvWaitKey( int delay )
1260 if(thread_started && g_thread_self()!=window_thread){
1264 // wait for signal or timeout if delay > 0
1267 g_get_current_time(&timer);
1268 g_time_val_add(&timer, delay*1000);
1269 expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
1272 g_cond_wait(cond_have_key, last_key_mutex);
1275 my_last_key = last_key;
1276 g_mutex_unlock(last_key_mutex);
1277 if(expired || hg_windows==0){
1287 timer = g_timeout_add( delay, icvAlarm, &expired );
1289 while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 )
1292 if( delay > 0 && !expired )
1293 g_source_remove(timer);