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.
42 #include "precomp.hpp"
49 #include "gdk/gdkkeysyms.h"
53 #include <gtk/gtkgl.h>
58 // TODO Fix the initial window size when flags=0. Right now the initial window is by default
59 // 320x240 size. A better default would be actual size of the image. Problem
60 // is determining desired window size with trackbars while still allowing resizing.
62 // Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio
63 // in totem/src/backend/bacon-video-widget-xine.c
65 ////////////////////////////////////////////////////////////
66 // CvImageWidget GTK Widget Public API
67 ////////////////////////////////////////////////////////////
68 typedef struct _CvImageWidget CvImageWidget;
69 typedef struct _CvImageWidgetClass CvImageWidgetClass;
71 struct _CvImageWidget {
73 CvMat * original_image;
78 struct _CvImageWidgetClass
80 GtkWidgetClass parent_class;
84 /** Allocate new image viewer widget */
85 GtkWidget* cvImageWidgetNew (int flags);
87 /** Set the image to display in the widget */
88 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr);
90 // standard GTK object macros
91 #define CV_IMAGE_WIDGET(obj) GTK_CHECK_CAST (obj, cvImageWidget_get_type (), CvImageWidget)
92 #define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass)
93 #define CV_IS_IMAGE_WIDGET(obj) GTK_CHECK_TYPE (obj, cvImageWidget_get_type ())
95 /////////////////////////////////////////////////////////////////////////////
96 // Private API ////////////////////////////////////////////////////////
97 /////////////////////////////////////////////////////////////////////////////
98 GtkType cvImageWidget_get_type (void);
100 static GtkWidgetClass * parent_class = NULL;
102 // flag to help size initial window
103 #define CV_WINDOW_NO_IMAGE 2
105 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){
109 //printf("cvImageWidgetSetImage\n");
111 if( CV_IS_IMAGE_HDR( arr ))
112 origin = ((IplImage*)arr)->origin;
114 mat = cvGetMat(arr, &stub);
116 if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){
117 cvReleaseMat( &widget->original_image );
119 if(!widget->original_image){
120 widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 );
121 gtk_widget_queue_resize( GTK_WIDGET( widget ) );
123 cvConvertImage( mat, widget->original_image,
124 (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
125 if(widget->scaled_image){
126 cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA );
129 // window does not refresh without this
130 gtk_widget_queue_draw( GTK_WIDGET(widget) );
134 cvImageWidgetNew (int flags)
136 CvImageWidget *image_widget;
138 image_widget = CV_IMAGE_WIDGET( gtk_type_new (cvImageWidget_get_type ()) );
139 image_widget->original_image = 0;
140 image_widget->scaled_image = 0;
141 image_widget->flags = flags | CV_WINDOW_NO_IMAGE;
143 return GTK_WIDGET (image_widget);
147 cvImageWidget_realize (GtkWidget *widget)
149 GdkWindowAttr attributes;
150 gint attributes_mask;
152 //printf("cvImageWidget_realize\n");
153 g_return_if_fail (widget != NULL);
154 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
156 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
158 attributes.x = widget->allocation.x;
159 attributes.y = widget->allocation.y;
160 attributes.width = widget->allocation.width;
161 attributes.height = widget->allocation.height;
162 attributes.wclass = GDK_INPUT_OUTPUT;
163 attributes.window_type = GDK_WINDOW_CHILD;
164 attributes.event_mask = gtk_widget_get_events (widget) |
165 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
166 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
167 attributes.visual = gtk_widget_get_visual (widget);
168 attributes.colormap = gtk_widget_get_colormap (widget);
170 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
171 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
173 widget->style = gtk_style_attach (widget->style, widget->window);
175 gdk_window_set_user_data (widget->window, widget);
177 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
180 static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){
181 float aspect = (float)im_width/(float)im_height;
182 float max_aspect = (float)max_width/(float)max_height;
183 if(aspect > max_aspect){
184 return cvSize( max_width, cvRound(max_width/aspect) );
186 return cvSize( cvRound(max_height*aspect), max_height );
190 cvImageWidget_size_request (GtkWidget *widget,
191 GtkRequisition *requisition)
193 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
195 //printf("cvImageWidget_size_request ");
196 // the case the first time cvShowImage called or when AUTOSIZE
197 if( image_widget->original_image &&
198 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
199 (image_widget->flags & CV_WINDOW_NO_IMAGE)))
201 //printf("original ");
202 requisition->width = image_widget->original_image->cols;
203 requisition->height = image_widget->original_image->rows;
206 else if(image_widget->scaled_image){
208 requisition->width = image_widget->scaled_image->cols;
209 requisition->height = image_widget->scaled_image->rows;
211 // the case before cvShowImage called
213 //printf("default ");
214 requisition->width = 320;
215 requisition->height = 240;
217 //printf("%d %d\n",requisition->width, requisition->height);
220 static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){
221 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
223 //printf("cvImageWidget_set_size %d %d\n", max_width, max_height);
225 // don't allow to set the size
226 if(image_widget->flags & CV_WINDOW_AUTOSIZE) return;
227 if(!image_widget->original_image) return;
229 CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols,
230 image_widget->original_image->rows, max_width, max_height );
232 if( image_widget->scaled_image &&
233 ( image_widget->scaled_image->cols != scaled_image_size.width ||
234 image_widget->scaled_image->rows != scaled_image_size.height ))
236 cvReleaseMat( &image_widget->scaled_image );
238 if( !image_widget->scaled_image ){
239 image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 );
243 assert( image_widget->scaled_image );
247 cvImageWidget_size_allocate (GtkWidget *widget,
248 GtkAllocation *allocation)
250 CvImageWidget *image_widget;
252 //printf("cvImageWidget_size_allocate\n");
253 g_return_if_fail (widget != NULL);
254 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
255 g_return_if_fail (allocation != NULL);
257 widget->allocation = *allocation;
258 image_widget = CV_IMAGE_WIDGET (widget);
261 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){
262 // (re) allocated scaled image
263 if( image_widget->flags & CV_WINDOW_NO_IMAGE ){
264 cvImageWidget_set_size( widget, image_widget->original_image->cols,
265 image_widget->original_image->rows);
268 cvImageWidget_set_size( widget, allocation->width, allocation->height );
270 cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA );
273 if (GTK_WIDGET_REALIZED (widget))
275 image_widget = CV_IMAGE_WIDGET (widget);
277 if( image_widget->original_image &&
278 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
279 (image_widget->flags & CV_WINDOW_NO_IMAGE)) )
281 widget->allocation.width = image_widget->original_image->cols;
282 widget->allocation.height = image_widget->original_image->rows;
283 gdk_window_move_resize( widget->window, allocation->x, allocation->y,
284 image_widget->original_image->cols, image_widget->original_image->rows );
285 if(image_widget->flags & CV_WINDOW_NO_IMAGE){
286 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
287 gtk_widget_queue_resize( GTK_WIDGET(widget) );
291 gdk_window_move_resize (widget->window,
292 allocation->x, allocation->y,
293 allocation->width, allocation->height );
300 cvImageWidget_destroy (GtkObject *object)
302 CvImageWidget *image_widget;
304 g_return_if_fail (object != NULL);
305 g_return_if_fail (CV_IS_IMAGE_WIDGET (object));
307 image_widget = CV_IMAGE_WIDGET (object);
309 cvReleaseMat( &image_widget->scaled_image );
310 cvReleaseMat( &image_widget->original_image );
312 if (GTK_OBJECT_CLASS (parent_class)->destroy)
313 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
316 static void cvImageWidget_class_init (CvImageWidgetClass * klass)
318 GtkObjectClass *object_class;
319 GtkWidgetClass *widget_class;
321 object_class = (GtkObjectClass*) klass;
322 widget_class = (GtkWidgetClass*) klass;
324 parent_class = GTK_WIDGET_CLASS( gtk_type_class (gtk_widget_get_type ()) );
326 object_class->destroy = cvImageWidget_destroy;
328 widget_class->realize = cvImageWidget_realize;
329 widget_class->size_request = cvImageWidget_size_request;
330 widget_class->size_allocate = cvImageWidget_size_allocate;
331 widget_class->button_press_event = NULL;
332 widget_class->button_release_event = NULL;
333 widget_class->motion_notify_event = NULL;
337 cvImageWidget_init (CvImageWidget *image_widget)
339 image_widget->original_image=0;
340 image_widget->scaled_image=0;
341 image_widget->flags=0;
344 GtkType cvImageWidget_get_type (void){
345 static GtkType image_type = 0;
349 static const GtkTypeInfo image_info =
351 (gchar*)"CvImageWidget",
352 sizeof (CvImageWidget),
353 sizeof (CvImageWidgetClass),
354 (GtkClassInitFunc) cvImageWidget_class_init,
355 (GtkObjectInitFunc) cvImageWidget_init,
356 /* reserved_1 */ NULL,
357 /* reserved_1 */ NULL,
358 (GtkClassInitFunc) NULL
361 image_type = gtk_type_unique (GTK_TYPE_WIDGET, &image_info);
366 /////////////////////////////////////////////////////////////////////////////
368 /////////////////////////////////////////////////////////////////////////////
373 typedef struct CvTrackbar
383 CvTrackbarCallback notify;
384 CvTrackbarCallback2 notify2;
390 typedef struct CvWindow
402 int status;//0 normal, 1 fullscreen (YV)
404 CvMouseCallback on_mouse;
405 void* on_mouse_param;
418 CvOpenGlDrawCallback glDrawCallback;
425 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
426 static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
427 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
428 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
431 int thread_started=0;
432 static gpointer icvWindowThreadLoop();
433 GMutex* last_key_mutex;
434 GCond* cond_have_key;
435 GMutex* window_mutex;
436 GThread* window_thread;
437 GtkWidget* cvTopLevelWidget = 0;
440 static int last_key = -1;
441 static CvWindow* hg_windows = 0;
443 CV_IMPL int cvInitSystem( int argc, char** argv )
445 static int wasInitialized = 0;
447 // check initialization status
448 if( !wasInitialized )
452 gtk_disable_setlocale();
453 gtk_init( &argc, &argv );
456 gtk_gl_init(&argc, &argv);
465 CV_IMPL int cvStartWindowThread(){
467 cvInitSystem(0,NULL);
468 if (!thread_started) {
469 if (!g_thread_supported ()) {
470 /* the GThread system wasn't inited, so init it */
474 // this mutex protects the window resources
475 window_mutex = g_mutex_new();
477 // protects the 'last key pressed' variable
478 last_key_mutex = g_mutex_new();
480 // conditional that indicates a key has been pressed
481 cond_have_key = g_cond_new();
483 // this is the window update thread
484 window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
487 thread_started = window_thread!=NULL;
488 return thread_started;
495 gpointer icvWindowThreadLoop(){
497 g_mutex_lock(window_mutex);
498 gtk_main_iteration_do(FALSE);
499 g_mutex_unlock(window_mutex);
509 #define CV_LOCK_MUTEX() \
510 if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { }
512 #define CV_UNLOCK_MUTEX() \
513 if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { }
516 #define CV_LOCK_MUTEX()
517 #define CV_UNLOCK_MUTEX()
520 static CvWindow* icvFindWindowByName( const char* name )
522 CvWindow* window = hg_windows;
523 while( window != 0 && strcmp(name, window->name) != 0 )
524 window = window->next;
529 static CvWindow* icvWindowByWidget( GtkWidget* widget )
531 CvWindow* window = hg_windows;
533 while( window != 0 && window->widget != widget &&
534 window->frame != widget && window->paned != widget )
535 window = window->next;
540 double cvGetModeWindow_GTK(const char* name)//YV
544 CV_FUNCNAME( "cvGetModeWindow_GTK" );
551 CV_ERROR( CV_StsNullPtr, "NULL name string" );
553 window = icvFindWindowByName( name );
555 CV_ERROR( CV_StsNullPtr, "NULL window" );
558 result = window->status;
566 void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
569 CV_FUNCNAME( "cvSetModeWindow_GTK" );
576 CV_ERROR( CV_StsNullPtr, "NULL name string" );
578 window = icvFindWindowByName( name );
580 CV_ERROR( CV_StsNullPtr, "NULL window" );
582 if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
585 //so easy to do fullscreen here, Linux rocks !
587 if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
590 gtk_window_unfullscreen(GTK_WINDOW(window->frame));
591 window->status=CV_WINDOW_NORMAL;
596 if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
599 gtk_window_fullscreen(GTK_WINDOW(window->frame));
600 window->status=CV_WINDOW_FULLSCREEN;
609 double cvGetPropWindowAutoSize_GTK(const char* name)
613 CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" );
620 CV_ERROR( CV_StsNullPtr, "NULL name string" );
622 window = icvFindWindowByName( name );
624 EXIT; // keep silence here
626 result = window->flags & CV_WINDOW_AUTOSIZE;
633 double cvGetRatioWindow_GTK(const char* name)
637 CV_FUNCNAME( "cvGetRatioWindow_GTK" );
644 CV_ERROR( CV_StsNullPtr, "NULL name string" );
646 window = icvFindWindowByName( name );
648 EXIT; // keep silence here
650 result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
657 double cvGetOpenGlProp_GTK(const char* name)
662 CV_FUNCNAME( "cvGetOpenGlProp_GTK" );
669 CV_ERROR( CV_StsNullPtr, "NULL name string" );
671 window = icvFindWindowByName( name );
673 EXIT; // keep silence here
675 result = window->useGl;
692 void createGlContext(CvWindow* window)
694 GdkGLConfig* glconfig;
696 CV_FUNCNAME( "createGlContext" );
700 // Try double-buffered visual
701 glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
703 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
705 // Set OpenGL-capability to the widget
706 if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))
707 CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
709 window->useGl = true;
714 void drawGl(CvWindow* window)
716 CV_FUNCNAME( "drawGl" );
720 GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
721 GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
723 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
724 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
726 glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);
728 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
730 if (window->glDrawCallback)
731 window->glDrawCallback(window->glDrawData);
733 if (gdk_gl_drawable_is_double_buffered (gldrawable))
734 gdk_gl_drawable_swap_buffers(gldrawable);
738 gdk_gl_drawable_gl_end(gldrawable);
744 #endif // HAVE_OPENGL
747 static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
750 CvWindow* window = (CvWindow*)data;
761 CvImageWidget *image_widget;
763 g_return_val_if_fail (widget != NULL, FALSE);
764 g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
765 g_return_val_if_fail (event != NULL, FALSE);
767 if (event->count > 0)
770 image_widget = CV_IMAGE_WIDGET (widget);
772 gdk_window_clear_area (widget->window,
774 widget->allocation.width,
775 widget->allocation.height);
776 if( image_widget->scaled_image ){
777 // center image in available region
778 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
779 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
781 gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
782 x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
783 MIN(image_widget->scaled_image->rows, widget->allocation.height),
784 GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
786 else if( image_widget->original_image ){
787 gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
789 MIN(image_widget->original_image->cols, widget->allocation.width),
790 MIN(image_widget->original_image->rows, widget->allocation.height),
791 GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
796 CV_IMPL int cvNamedWindow( const char* name, int flags )
799 CV_FUNCNAME( "cvNamedWindow" );
806 cvInitSystem(1,(char**)&name);
808 CV_ERROR( CV_StsNullPtr, "NULL name string" );
810 // Check the name in the storage
811 if( icvFindWindowByName( name ) != 0 )
818 CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
819 memset( window, 0, sizeof(*window));
820 window->name = (char*)(window + 1);
821 memcpy( window->name, name, len + 1 );
822 window->flags = flags;
823 window->signature = CV_WINDOW_MAGIC_VAL;
824 window->last_key = 0;
825 window->on_mouse = 0;
826 window->on_mouse_param = 0;
827 memset( &window->toolbar, 0, sizeof(window->toolbar));
828 window->next = hg_windows;
830 window->status = CV_WINDOW_NORMAL;//YV
834 window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
836 window->paned = gtk_vbox_new( FALSE, 0 );
837 window->widget = cvImageWidgetNew( flags );
838 gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
839 gtk_widget_show( window->widget );
840 gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
841 gtk_widget_show( window->paned );
844 if (flags & CV_WINDOW_OPENGL)
845 CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
847 if (flags & CV_WINDOW_OPENGL)
848 createGlContext(window);
850 window->glDrawCallback = 0;
851 window->glDrawData = 0;
855 // configure event handlers
856 // TODO -- move this to CvImageWidget ?
857 gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event",
858 GTK_SIGNAL_FUNC(icvOnKeyPress), window );
859 gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event",
860 GTK_SIGNAL_FUNC(icvOnMouse), window );
861 gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event",
862 GTK_SIGNAL_FUNC(icvOnMouse), window );
863 gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event",
864 GTK_SIGNAL_FUNC(icvOnMouse), window );
865 gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event",
866 GTK_SIGNAL_FUNC(icvOnClose), window );
867 gtk_signal_connect( GTK_OBJECT(window->widget), "expose-event",
868 GTK_SIGNAL_FUNC(cvImageWidget_expose), window );
870 gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
872 gtk_widget_show( window->frame );
873 gtk_window_set_title( GTK_WINDOW(window->frame), name );
876 hg_windows->prev = window;
879 gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
882 // allow window to be resized
883 if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
884 GdkGeometry geometry;
885 geometry.min_width = 50;
886 geometry.min_height = 50;
887 gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
888 &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
895 cvSetOpenGlContext(name);
907 CV_IMPL void cvSetOpenGlContext(const char* name)
910 GdkGLContext* glcontext;
911 GdkGLDrawable* gldrawable;
913 CV_FUNCNAME( "cvSetOpenGlContext" );
918 CV_ERROR( CV_StsNullPtr, "NULL name string" );
920 window = icvFindWindowByName( name );
922 CV_ERROR( CV_StsNullPtr, "NULL window" );
925 CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
927 glcontext = gtk_widget_get_gl_context(window->widget);
928 gldrawable = gtk_widget_get_gl_drawable(window->widget);
930 if (!gdk_gl_drawable_make_current(gldrawable, glcontext))
931 CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
936 CV_IMPL void cvUpdateWindow(const char* name)
938 CV_FUNCNAME( "cvUpdateWindow" );
945 CV_ERROR( CV_StsNullPtr, "NULL name string" );
947 window = icvFindWindowByName( name );
951 // window does not refresh without this
952 gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
957 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
961 CV_FUNCNAME( "cvCreateOpenGLCallback" );
966 CV_ERROR( CV_StsNullPtr, "NULL name string" );
968 window = icvFindWindowByName( name );
973 CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
975 window->glDrawCallback = callback;
976 window->glDrawData = userdata;
981 #endif // HAVE_OPENGL
986 static void icvDeleteWindow( CvWindow* window )
988 CvTrackbar* trackbar;
991 window->prev->next = window->next;
993 hg_windows = window->next;
996 window->next->prev = window->prev;
998 window->prev = window->next = 0;
1000 gtk_widget_destroy( window->frame );
1002 for( trackbar = window->toolbar.first; trackbar != 0; )
1004 CvTrackbar* next = trackbar->next;
1005 cvFree( &trackbar );
1011 // if last window, send key press signal
1012 // to jump out of any waiting cvWaitKey's
1013 if(hg_windows==0 && thread_started){
1014 g_cond_broadcast(cond_have_key);
1020 CV_IMPL void cvDestroyWindow( const char* name )
1022 CV_FUNCNAME( "cvDestroyWindow" );
1029 CV_ERROR( CV_StsNullPtr, "NULL name string" );
1031 window = icvFindWindowByName( name );
1035 // note that it is possible for the update thread to run this function
1036 // if there is a call to cvShowImage in a mouse callback
1037 // (this would produce a deadlock on window_mutex)
1040 icvDeleteWindow( window );
1049 cvDestroyAllWindows( void )
1055 CvWindow* window = hg_windows;
1056 icvDeleteWindow( window );
1061 // CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
1062 // CvSize window_size;
1063 // GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
1064 // gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
1065 // &window_size.width, &window_size.height );
1067 // window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
1068 // window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
1070 // return window_size;
1074 cvShowImage( const char* name, const CvArr* arr )
1076 CV_FUNCNAME( "cvShowImage" );
1083 CV_ERROR( CV_StsNullPtr, "NULL name" );
1087 window = icvFindWindowByName(name);
1090 cvNamedWindow(name, 1);
1091 window = icvFindWindowByName(name);
1100 CvMat* mat = cvGetMat(arr, &stub);
1102 cv::imshow(name, im);
1107 CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
1108 cvImageWidgetSetImage( image_widget, arr );
1116 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1118 CV_FUNCNAME( "cvResizeWindow" );
1123 CvImageWidget * image_widget;
1126 CV_ERROR( CV_StsNullPtr, "NULL name" );
1128 window = icvFindWindowByName(name);
1132 image_widget = CV_IMAGE_WIDGET( window->widget );
1133 //if(image_widget->flags & CV_WINDOW_AUTOSIZE)
1138 gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
1139 gtk_window_resize( GTK_WINDOW(window->frame), width, height );
1141 // disable initial resize since presumably user wants to keep
1143 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
1151 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1153 CV_FUNCNAME( "cvMoveWindow" );
1160 CV_ERROR( CV_StsNullPtr, "NULL name" );
1162 window = icvFindWindowByName(name);
1168 gtk_window_move( GTK_WINDOW(window->frame), x, y );
1177 icvFindTrackbarByName( const CvWindow* window, const char* name )
1179 CvTrackbar* trackbar = window->toolbar.first;
1181 for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
1188 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
1189 int* val, int count, CvTrackbarCallback on_notify,
1190 CvTrackbarCallback2 on_notify2, void* userdata )
1194 CV_FUNCNAME( "icvCreateTrackbar" );
1198 /*char slider_name[32];*/
1199 CvWindow* window = 0;
1200 CvTrackbar* trackbar = 0;
1202 if( !window_name || !trackbar_name )
1203 CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
1206 CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
1208 window = icvFindWindowByName(window_name);
1212 trackbar = icvFindTrackbarByName(window,trackbar_name);
1218 int len = strlen(trackbar_name);
1219 trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
1220 memset( trackbar, 0, sizeof(*trackbar));
1221 trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
1222 trackbar->name = (char*)(trackbar+1);
1223 memcpy( trackbar->name, trackbar_name, len + 1 );
1224 trackbar->parent = window;
1225 trackbar->next = window->toolbar.first;
1226 window->toolbar.first = trackbar;
1228 GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
1229 GtkWidget* hscale_label = gtk_label_new( trackbar_name );
1230 GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
1231 gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS );
1232 gtk_scale_set_digits( GTK_SCALE(hscale), 0 );
1233 //gtk_scale_set_value_pos( hscale, GTK_POS_TOP );
1234 gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );
1236 trackbar->widget = hscale;
1237 gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );
1238 gtk_widget_show( hscale_label );
1239 gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );
1240 gtk_widget_show( hscale );
1241 gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );
1242 gtk_widget_show( hscale_box );
1253 gtk_range_set_value( GTK_RANGE(trackbar->widget), value );
1254 trackbar->pos = value;
1255 trackbar->data = val;
1258 trackbar->maxval = count;
1259 trackbar->notify = on_notify;
1260 trackbar->notify2 = on_notify2;
1261 trackbar->userdata = userdata;
1262 gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed",
1263 GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar );
1265 // queue a widget resize to trigger a window resize to
1266 // compensate for the addition of trackbars
1267 gtk_widget_queue_resize( GTK_WIDGET(window->widget) );
1281 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1282 int* val, int count, CvTrackbarCallback on_notify )
1284 return icvCreateTrackbar(trackbar_name, window_name, val, count,
1290 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
1291 int* val, int count, CvTrackbarCallback2 on_notify2,
1294 return icvCreateTrackbar(trackbar_name, window_name, val, count,
1295 0, on_notify2, userdata);
1300 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1302 CV_FUNCNAME( "cvSetMouseCallback" );
1306 CvWindow* window = 0;
1309 CV_ERROR( CV_StsNullPtr, "NULL window name" );
1311 window = icvFindWindowByName(window_name);
1315 window->on_mouse = on_mouse;
1316 window->on_mouse_param = param;
1322 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1326 CV_FUNCNAME( "cvGetTrackbarPos" );
1331 CvTrackbar* trackbar = 0;
1333 if( trackbar_name == 0 || window_name == 0 )
1334 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1336 window = icvFindWindowByName( window_name );
1338 trackbar = icvFindTrackbarByName( window, trackbar_name );
1341 pos = trackbar->pos;
1349 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1351 CV_FUNCNAME( "cvSetTrackbarPos" );
1356 CvTrackbar* trackbar = 0;
1358 if( trackbar_name == 0 || window_name == 0 )
1359 CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
1361 window = icvFindWindowByName( window_name );
1363 trackbar = icvFindTrackbarByName( window, trackbar_name );
1370 if( pos > trackbar->maxval )
1371 pos = trackbar->maxval;
1376 gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
1384 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1388 CV_FUNCNAME( "cvGetWindowHandle" );
1394 if( window_name == 0 )
1395 CV_ERROR( CV_StsNullPtr, "NULL window name" );
1397 window = icvFindWindowByName( window_name );
1399 widget = (void*)window->widget;
1407 CV_IMPL const char* cvGetWindowName( void* window_handle )
1409 const char* window_name = "";
1411 CV_FUNCNAME( "cvGetWindowName" );
1417 if( window_handle == 0 )
1418 CV_ERROR( CV_StsNullPtr, "NULL window" );
1420 window = icvWindowByWidget( (GtkWidget*)window_handle );
1422 window_name = window->name;
1429 static gboolean icvOnKeyPress( GtkWidget * /*widget*/,
1430 GdkEventKey* event, gpointer /*user_data*/ )
1434 switch( event->keyval )
1447 code = event->keyval;
1450 code |= event->state << 16;
1453 if(thread_started) g_mutex_lock(last_key_mutex);
1460 // signal any waiting threads
1461 g_cond_broadcast(cond_have_key);
1462 g_mutex_unlock(last_key_mutex);
1470 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
1472 int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
1473 CvTrackbar* trackbar = (CvTrackbar*)user_data;
1475 if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
1476 trackbar->widget == widget )
1478 trackbar->pos = pos;
1479 if( trackbar->data )
1480 *trackbar->data = pos;
1481 if( trackbar->notify2 )
1482 trackbar->notify2(pos, trackbar->userdata);
1483 else if( trackbar->notify )
1484 trackbar->notify(pos);
1488 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
1490 CvWindow* window = (CvWindow*)user_data;
1491 if( window->signature == CV_WINDOW_MAGIC_VAL &&
1492 window->frame == widget )
1494 icvDeleteWindow(window);
1500 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
1502 // TODO move this logic to CvImageWidget
1503 CvWindow* window = (CvWindow*)user_data;
1504 CvPoint2D32f pt32f = {-1., -1.};
1505 CvPoint pt = {-1,-1};
1506 int cv_event = -1, state = 0;
1507 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
1509 if( window->signature != CV_WINDOW_MAGIC_VAL ||
1510 window->widget != widget || !window->widget ||
1511 !window->on_mouse /*|| !image_widget->original_image*/)
1514 if( event->type == GDK_MOTION_NOTIFY )
1516 GdkEventMotion* event_motion = (GdkEventMotion*)event;
1518 cv_event = CV_EVENT_MOUSEMOVE;
1519 pt32f.x = cvRound(event_motion->x);
1520 pt32f.y = cvRound(event_motion->y);
1521 state = event_motion->state;
1523 else if( event->type == GDK_BUTTON_PRESS ||
1524 event->type == GDK_BUTTON_RELEASE ||
1525 event->type == GDK_2BUTTON_PRESS )
1527 GdkEventButton* event_button = (GdkEventButton*)event;
1528 pt32f.x = cvRound(event_button->x);
1529 pt32f.y = cvRound(event_button->y);
1532 if( event_button->type == GDK_BUTTON_PRESS )
1534 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
1535 event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
1536 event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
1538 else if( event_button->type == GDK_BUTTON_RELEASE )
1540 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
1541 event_button->button == 2 ? CV_EVENT_MBUTTONUP :
1542 event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
1544 else if( event_button->type == GDK_2BUTTON_PRESS )
1546 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
1547 event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
1548 event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
1550 state = event_button->state;
1553 if( cv_event >= 0 ){
1554 // scale point if image is scaled
1555 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
1556 image_widget->original_image &&
1557 image_widget->scaled_image ){
1558 // image origin is not necessarily at (0,0)
1559 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1560 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1561 pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/
1562 image_widget->scaled_image->cols );
1563 pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/
1564 image_widget->scaled_image->rows );
1567 pt = cvPointFrom32f( pt32f );
1570 // if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
1571 // (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
1573 int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
1574 (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
1575 (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
1576 (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
1577 (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
1578 (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
1579 window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
1587 static gboolean icvAlarm( gpointer user_data )
1589 *(int*)user_data = 1;
1594 CV_IMPL int cvWaitKey( int delay )
1597 if(thread_started && g_thread_self()!=window_thread){
1601 // wait for signal or timeout if delay > 0
1604 g_get_current_time(&timer);
1605 g_time_val_add(&timer, delay*1000);
1606 expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
1609 g_cond_wait(cond_have_key, last_key_mutex);
1612 my_last_key = last_key;
1613 g_mutex_unlock(last_key_mutex);
1614 if(expired || hg_windows==0){
1624 timer = g_timeout_add( delay, icvAlarm, &expired );
1626 while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 )
1629 if( delay > 0 && !expired )
1630 g_source_remove(timer);