/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" #ifndef WIN32 #ifdef HAVE_GTK #include "gtk/gtk.h" #include "gdk/gdkkeysyms.h" #include /*#if _MSC_VER >= 1200 #pragma warning( disable: 4505 ) #pragma comment(lib,"gtk-win32-2.0.lib") #pragma comment(lib,"glib-2.0.lib") #pragma comment(lib,"gobject-2.0.lib") #pragma comment(lib,"gdk-win32-2.0.lib") #pragma comment(lib,"gdk_pixbuf-2.0.lib") #endif*/ // TODO Fix the initial window size when flags=0. Right now the initial window is by default // 320x240 size. A better default would be actual size of the image. Problem // is determining desired window size with trackbars while still allowing resizing. // // Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio // in totem/src/backend/bacon-video-widget-xine.c //////////////////////////////////////////////////////////// // CvImageWidget GTK Widget Public API //////////////////////////////////////////////////////////// typedef struct _CvImageWidget CvImageWidget; typedef struct _CvImageWidgetClass CvImageWidgetClass; struct _CvImageWidget { GtkWidget widget; CvMat * original_image; CvMat * scaled_image; int flags; }; struct _CvImageWidgetClass { GtkWidgetClass parent_class; }; /** Allocate new image viewer widget */ GtkWidget* cvImageWidgetNew (int flags); /** Set the image to display in the widget */ void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr); // standard GTK object macros #define CV_IMAGE_WIDGET(obj) GTK_CHECK_CAST (obj, cvImageWidget_get_type (), CvImageWidget) #define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass) #define CV_IS_IMAGE_WIDGET(obj) GTK_CHECK_TYPE (obj, cvImageWidget_get_type ()) ///////////////////////////////////////////////////////////////////////////// // Private API //////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// GtkType cvImageWidget_get_type (void); static GtkWidgetClass * parent_class = NULL; // flag to help size initial window #define CV_WINDOW_NO_IMAGE 2 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){ CvMat * mat, stub; int origin=0; //printf("cvImageWidgetSetImage\n"); if( CV_IS_IMAGE_HDR( arr )) origin = ((IplImage*)arr)->origin; mat = cvGetMat(arr, &stub); if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){ cvReleaseMat( &widget->original_image ); } if(!widget->original_image){ widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 ); gtk_widget_queue_resize( GTK_WIDGET( widget ) ); } cvConvertImage( mat, widget->original_image, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB ); if(widget->scaled_image){ cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA ); } // window does not refresh without this gtk_widget_queue_draw( GTK_WIDGET(widget) ); } GtkWidget* cvImageWidgetNew (int flags) { CvImageWidget *image_widget; image_widget = CV_IMAGE_WIDGET( gtk_type_new (cvImageWidget_get_type ()) ); image_widget->original_image = 0; image_widget->scaled_image = 0; image_widget->flags = flags | CV_WINDOW_NO_IMAGE; return GTK_WIDGET (image_widget); } static void cvImageWidget_realize (GtkWidget *widget) { CvImageWidget *image_widget; GdkWindowAttr attributes; gint attributes_mask; //printf("cvImageWidget_realize\n"); g_return_if_fail (widget != NULL); g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); image_widget = CV_IMAGE_WIDGET (widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_user_data (widget->window, widget); gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); } static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){ float aspect = (float)im_width/(float)im_height; float max_aspect = (float)max_width/(float)max_height; if(aspect > max_aspect){ return cvSize( max_width, cvRound(max_width/aspect) ); } return cvSize( cvRound(max_height*aspect), max_height ); } static void cvImageWidget_size_request (GtkWidget *widget, GtkRequisition *requisition) { CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); //printf("cvImageWidget_size_request "); // the case the first time cvShowImage called or when AUTOSIZE if( image_widget->original_image && ((image_widget->flags & CV_WINDOW_AUTOSIZE) || (image_widget->flags & CV_WINDOW_NO_IMAGE))) { //printf("original "); requisition->width = image_widget->original_image->cols; requisition->height = image_widget->original_image->rows; } // default case else if(image_widget->scaled_image){ //printf("scaled "); requisition->width = image_widget->scaled_image->cols; requisition->height = image_widget->scaled_image->rows; } // the case before cvShowImage called else{ //printf("default "); requisition->width = 320; requisition->height = 240; } //printf("%d %d\n",requisition->width, requisition->height); } static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){ CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); //printf("cvImageWidget_set_size %d %d\n", max_width, max_height); // don't allow to set the size if(image_widget->flags & CV_WINDOW_AUTOSIZE) return; if(!image_widget->original_image) return; CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols, image_widget->original_image->rows, max_width, max_height ); if( image_widget->scaled_image && ( image_widget->scaled_image->cols != scaled_image_size.width || image_widget->scaled_image->rows != scaled_image_size.height )) { cvReleaseMat( &image_widget->scaled_image ); } if( !image_widget->scaled_image ){ image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 ); } assert( image_widget->scaled_image ); } static void cvImageWidget_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { CvImageWidget *image_widget; //printf("cvImageWidget_size_allocate\n"); g_return_if_fail (widget != NULL); g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; image_widget = CV_IMAGE_WIDGET (widget); if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){ // (re) allocated scaled image if( image_widget->flags & CV_WINDOW_NO_IMAGE ){ cvImageWidget_set_size( widget, image_widget->original_image->cols, image_widget->original_image->rows); } else{ cvImageWidget_set_size( widget, allocation->width, allocation->height ); } cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA ); } if (GTK_WIDGET_REALIZED (widget)) { image_widget = CV_IMAGE_WIDGET (widget); if( image_widget->original_image && ((image_widget->flags & CV_WINDOW_AUTOSIZE) || (image_widget->flags & CV_WINDOW_NO_IMAGE)) ) { widget->allocation.width = image_widget->original_image->cols; widget->allocation.height = image_widget->original_image->rows; gdk_window_move_resize( widget->window, allocation->x, allocation->y, image_widget->original_image->cols, image_widget->original_image->rows ); if(image_widget->flags & CV_WINDOW_NO_IMAGE){ image_widget->flags &= ~CV_WINDOW_NO_IMAGE; gtk_widget_queue_resize( GTK_WIDGET(widget) ); } } else{ gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height ); } } } static gboolean cvImageWidget_expose( GtkWidget *widget, GdkEventExpose *event ) { CvImageWidget *image_widget; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (event->count > 0) return FALSE; image_widget = CV_IMAGE_WIDGET (widget); gdk_window_clear_area (widget->window, 0, 0, widget->allocation.width, widget->allocation.height); if( image_widget->scaled_image ){ // center image in available region int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width), MIN(image_widget->scaled_image->rows, widget->allocation.height), GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step ); } else if( image_widget->original_image ){ gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], 0, 0, MIN(image_widget->original_image->cols, widget->allocation.width), MIN(image_widget->original_image->rows, widget->allocation.height), GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step ); } return TRUE; } static void cvImageWidget_destroy (GtkObject *object) { CvImageWidget *image_widget; g_return_if_fail (object != NULL); g_return_if_fail (CV_IS_IMAGE_WIDGET (object)); image_widget = CV_IMAGE_WIDGET (object); cvReleaseMat( &image_widget->scaled_image ); cvReleaseMat( &image_widget->original_image ); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void cvImageWidget_class_init (CvImageWidgetClass * klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; parent_class = GTK_WIDGET_CLASS( gtk_type_class (gtk_widget_get_type ()) ); object_class->destroy = cvImageWidget_destroy; widget_class->realize = cvImageWidget_realize; widget_class->expose_event = cvImageWidget_expose; widget_class->size_request = cvImageWidget_size_request; widget_class->size_allocate = cvImageWidget_size_allocate; widget_class->button_press_event = NULL; widget_class->button_release_event = NULL; widget_class->motion_notify_event = NULL; } static void cvImageWidget_init (CvImageWidget *image_widget) { image_widget->original_image=0; image_widget->scaled_image=0; image_widget->flags=0; } GtkType cvImageWidget_get_type (void){ static GtkType image_type = 0; if (!image_type) { static const GtkTypeInfo image_info = { (gchar*)"CvImageWidget", sizeof (CvImageWidget), sizeof (CvImageWidgetClass), (GtkClassInitFunc) cvImageWidget_class_init, (GtkObjectInitFunc) cvImageWidget_init, /* reserved_1 */ NULL, /* reserved_1 */ NULL, (GtkClassInitFunc) NULL }; image_type = gtk_type_unique (GTK_TYPE_WIDGET, &image_info); } return image_type; } ///////////////////////////////////////////////////////////////////////////// // End CvImageWidget ///////////////////////////////////////////////////////////////////////////// struct CvWindow; typedef struct CvTrackbar { int signature; GtkWidget* widget; char* name; CvTrackbar* next; CvWindow* parent; int* data; int pos; int maxval; CvTrackbarCallback notify; CvTrackbarCallback2 notify2; void* userdata; } CvTrackbar; typedef struct CvWindow { int signature; GtkWidget* widget; GtkWidget* frame; GtkWidget* paned; char* name; CvWindow* prev; CvWindow* next; int last_key; int flags; int status;//0 normal, 1 fullscreen (YV) CvMouseCallback on_mouse; void* on_mouse_param; struct { int pos; int rows; CvTrackbar* first; } toolbar; } CvWindow; static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data ); static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data ); static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ); static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ); #ifdef HAVE_GTHREAD int thread_started=0; static gpointer icvWindowThreadLoop(); GMutex* last_key_mutex; GCond* cond_have_key; GMutex* window_mutex; GThread* window_thread; GtkWidget* cvTopLevelWidget = 0; #endif static int last_key = -1; static CvWindow* hg_windows = 0; CV_IMPL int cvInitSystem( int argc, char** argv ) { static int wasInitialized = 0; // check initialization status if( !wasInitialized ) { hg_windows = 0; gtk_init( &argc, &argv ); wasInitialized = 1; } return 0; } CV_IMPL int cvStartWindowThread(){ #ifdef HAVE_GTHREAD cvInitSystem(0,NULL); if (!thread_started) { if (!g_thread_supported ()) { /* the GThread system wasn't inited, so init it */ g_thread_init(NULL); } // this mutex protects the window resources window_mutex = g_mutex_new(); // protects the 'last key pressed' variable last_key_mutex = g_mutex_new(); // conditional that indicates a key has been pressed cond_have_key = g_cond_new(); // this is the window update thread window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop, NULL, TRUE, NULL); } thread_started = window_thread!=NULL; return thread_started; #else return 0; #endif } #ifdef HAVE_GTHREAD gpointer icvWindowThreadLoop(){ while(1){ g_mutex_lock(window_mutex); gtk_main_iteration_do(FALSE); g_mutex_unlock(window_mutex); // little sleep g_usleep(500); g_thread_yield(); } return NULL; } #define CV_LOCK_MUTEX() \ if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { } #define CV_UNLOCK_MUTEX() \ if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { } #else #define CV_LOCK_MUTEX() #define CV_UNLOCK_MUTEX() #endif static CvWindow* icvFindWindowByName( const char* name ) { CvWindow* window = hg_windows; while( window != 0 && strcmp(name, window->name) != 0 ) window = window->next; return window; } static CvWindow* icvWindowByWidget( GtkWidget* widget ) { CvWindow* window = hg_windows; while( window != 0 && window->widget != widget && window->frame != widget && window->paned != widget ) window = window->next; return window; } double cvGetMode_GTK(const char* name)//YV { double result = -1; CV_FUNCNAME( "cvGetMode_GTK" ); __BEGIN__; CvWindow* window; if(!name) CV_ERROR( CV_StsNullPtr, "NULL name string" ); window = icvFindWindowByName( name ); if( !window ) CV_ERROR( CV_StsNullPtr, "NULL window" ); CV_LOCK_MUTEX(); result = window->status; CV_UNLOCK_MUTEX(); __END__; return result; } void cvChangeMode_GTK( const char* name, double prop_value)//Yannick Verdie { CV_FUNCNAME( "cvChangeMode_GTK" ); __BEGIN__; CvWindow* window; if(!name) CV_ERROR( CV_StsNullPtr, "NULL name string" ); window = icvFindWindowByName( name ); if( !window ) CV_ERROR( CV_StsNullPtr, "NULL window" ); if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set EXIT; //so easy to do fullscreen here, Linux rocks ! if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL) { CV_LOCK_MUTEX(); gtk_window_unfullscreen(GTK_WINDOW(window->frame)); window->status=CV_WINDOW_NORMAL; CV_UNLOCK_MUTEX(); EXIT; } if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) { CV_LOCK_MUTEX(); gtk_window_fullscreen(GTK_WINDOW(window->frame)); window->status=CV_WINDOW_FULLSCREEN; CV_UNLOCK_MUTEX(); EXIT; } __END__; } CV_IMPL int cvNamedWindow( const char* name, int flags ) { int result = 0; CV_FUNCNAME( "cvNamedWindow" ); __BEGIN__; CvWindow* window; int len; cvInitSystem(1,(char**)&name); if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name string" ); // Check the name in the storage if( icvFindWindowByName( name ) != 0 ) { result = 1; EXIT; } len = strlen(name); CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1)); memset( window, 0, sizeof(*window)); window->name = (char*)(window + 1); memcpy( window->name, name, len + 1 ); window->flags = flags; window->signature = CV_WINDOW_MAGIC_VAL; window->last_key = 0; window->on_mouse = 0; window->on_mouse_param = 0; memset( &window->toolbar, 0, sizeof(window->toolbar)); window->next = hg_windows; window->prev = 0; window->status = CV_WINDOW_NORMAL;//YV CV_LOCK_MUTEX(); window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL ); window->paned = gtk_vbox_new( FALSE, 0 ); window->widget = cvImageWidgetNew( flags ); gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 ); gtk_widget_show( window->widget ); gtk_container_add( GTK_CONTAINER(window->frame), window->paned ); gtk_widget_show( window->paned ); // // configure event handlers // TODO -- move this to CvImageWidget ? gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event", GTK_SIGNAL_FUNC(icvOnKeyPress), window ); gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event", GTK_SIGNAL_FUNC(icvOnMouse), window ); gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event", GTK_SIGNAL_FUNC(icvOnMouse), window ); gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event", GTK_SIGNAL_FUNC(icvOnMouse), window ); gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event", GTK_SIGNAL_FUNC(icvOnClose), window ); gtk_widget_add_events (window->widget, GDK_EXPOSURE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ; gtk_widget_show( window->frame ); gtk_window_set_title( GTK_WINDOW(window->frame), name ); if( hg_windows ) hg_windows->prev = window; hg_windows = window; gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 ); // allow window to be resized if( (flags & CV_WINDOW_AUTOSIZE)==0 ){ GdkGeometry geometry; geometry.min_width = 50; geometry.min_height = 50; gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ), &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE)); } CV_UNLOCK_MUTEX(); result = 1; __END__; return result; } static void icvDeleteWindow( CvWindow* window ) { CvTrackbar* trackbar; if( window->prev ) window->prev->next = window->next; else hg_windows = window->next; if( window->next ) window->next->prev = window->prev; window->prev = window->next = 0; gtk_widget_destroy( window->frame ); for( trackbar = window->toolbar.first; trackbar != 0; ) { CvTrackbar* next = trackbar->next; cvFree( &trackbar ); trackbar = next; } cvFree( &window ); #ifdef HAVE_GTHREAD // if last window, send key press signal // to jump out of any waiting cvWaitKey's if(hg_windows==0 && thread_started){ g_cond_broadcast(cond_have_key); } #endif } CV_IMPL void cvDestroyWindow( const char* name ) { CV_FUNCNAME( "cvDestroyWindow" ); __BEGIN__; CvWindow* window; if(!name) CV_ERROR( CV_StsNullPtr, "NULL name string" ); window = icvFindWindowByName( name ); if( !window ) EXIT; // note that it is possible for the update thread to run this function // if there is a call to cvShowImage in a mouse callback // (this would produce a deadlock on window_mutex) CV_LOCK_MUTEX(); icvDeleteWindow( window ); CV_UNLOCK_MUTEX(); __END__; } CV_IMPL void cvDestroyAllWindows( void ) { CV_LOCK_MUTEX(); while( hg_windows ) { CvWindow* window = hg_windows; icvDeleteWindow( window ); } CV_UNLOCK_MUTEX(); } CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){ CvSize window_size; GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame ); gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window), &window_size.width, &window_size.height ); window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width; window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height; return window_size; } CV_IMPL void cvShowImage( const char* name, const CvArr* arr ) { CV_FUNCNAME( "cvShowImage" ); __BEGIN__; CvWindow* window; if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name" ); CV_LOCK_MUTEX(); window = icvFindWindowByName(name); if(!window) { cvNamedWindow(name, 1); window = icvFindWindowByName(name); } if( window && arr ){ CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget ); cvImageWidgetSetImage( image_widget, arr ); } CV_UNLOCK_MUTEX(); __END__; } CV_IMPL void cvResizeWindow(const char* name, int width, int height ) { CV_FUNCNAME( "cvResizeWindow" ); __BEGIN__; CvWindow* window; CvImageWidget * image_widget; if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name" ); window = icvFindWindowByName(name); if(!window) EXIT; image_widget = CV_IMAGE_WIDGET( window->widget ); if(image_widget->flags & CV_WINDOW_AUTOSIZE) EXIT; CV_LOCK_MUTEX(); gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 ); gtk_window_resize( GTK_WINDOW(window->frame), width, height ); // disable initial resize since presumably user wants to keep // this window size image_widget->flags &= ~CV_WINDOW_NO_IMAGE; CV_UNLOCK_MUTEX(); __END__; } CV_IMPL void cvMoveWindow( const char* name, int x, int y ) { CV_FUNCNAME( "cvMoveWindow" ); __BEGIN__; CvWindow* window; if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name" ); window = icvFindWindowByName(name); if(!window) EXIT; CV_LOCK_MUTEX(); gtk_window_move( GTK_WINDOW(window->frame), x, y ); CV_UNLOCK_MUTEX(); __END__; } static CvTrackbar* icvFindTrackbarByName( const CvWindow* window, const char* name ) { CvTrackbar* trackbar = window->toolbar.first; for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next ) ; return trackbar; } static int icvCreateTrackbar( const char* trackbar_name, const char* window_name, int* val, int count, CvTrackbarCallback on_notify, CvTrackbarCallback2 on_notify2, void* userdata ) { int result = 0; CV_FUNCNAME( "icvCreateTrackbar" ); __BEGIN__; /*char slider_name[32];*/ CvWindow* window = 0; CvTrackbar* trackbar = 0; if( !window_name || !trackbar_name ) CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" ); if( count <= 0 ) CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" ); window = icvFindWindowByName(window_name); if( !window ) EXIT; trackbar = icvFindTrackbarByName(window,trackbar_name); CV_LOCK_MUTEX(); if( !trackbar ) { int len = strlen(trackbar_name); trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1); memset( trackbar, 0, sizeof(*trackbar)); trackbar->signature = CV_TRACKBAR_MAGIC_VAL; trackbar->name = (char*)(trackbar+1); memcpy( trackbar->name, trackbar_name, len + 1 ); trackbar->parent = window; trackbar->next = window->toolbar.first; window->toolbar.first = trackbar; GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 ); GtkWidget* hscale_label = gtk_label_new( trackbar_name ); GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 ); gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS ); gtk_scale_set_digits( GTK_SCALE(hscale), 0 ); //gtk_scale_set_value_pos( hscale, GTK_POS_TOP ); gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE ); trackbar->widget = hscale; gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 ); gtk_widget_show( hscale_label ); gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 ); gtk_widget_show( hscale ); gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 ); gtk_widget_show( hscale_box ); } if( val ) { int value = *val; if( value < 0 ) value = 0; if( value > count ) value = count; gtk_range_set_value( GTK_RANGE(trackbar->widget), value ); trackbar->pos = value; trackbar->data = val; } trackbar->maxval = count; trackbar->notify = on_notify; trackbar->notify2 = on_notify2; trackbar->userdata = userdata; gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed", GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar ); // queue a widget resize to trigger a window resize to // compensate for the addition of trackbars gtk_widget_queue_resize( GTK_WIDGET(window->widget) ); CV_UNLOCK_MUTEX(); result = 1; __END__; return result; } CV_IMPL int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* val, int count, CvTrackbarCallback on_notify ) { return icvCreateTrackbar(trackbar_name, window_name, val, count, on_notify, 0, 0); } CV_IMPL int cvCreateTrackbar2( const char* trackbar_name, const char* window_name, int* val, int count, CvTrackbarCallback2 on_notify2, void* userdata ) { return icvCreateTrackbar(trackbar_name, window_name, val, count, 0, on_notify2, userdata); } CV_IMPL void cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param ) { CV_FUNCNAME( "cvSetMouseCallback" ); __BEGIN__; CvWindow* window = 0; if( !window_name ) CV_ERROR( CV_StsNullPtr, "NULL window name" ); window = icvFindWindowByName(window_name); if( !window ) EXIT; window->on_mouse = on_mouse; window->on_mouse_param = param; __END__; } CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) { int pos = -1; CV_FUNCNAME( "cvGetTrackbarPos" ); __BEGIN__; CvWindow* window; CvTrackbar* trackbar = 0; if( trackbar_name == 0 || window_name == 0 ) CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); window = icvFindWindowByName( window_name ); if( window ) trackbar = icvFindTrackbarByName( window, trackbar_name ); if( trackbar ) pos = trackbar->pos; __END__; return pos; } CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) { CV_FUNCNAME( "cvSetTrackbarPos" ); __BEGIN__; CvWindow* window; CvTrackbar* trackbar = 0; if( trackbar_name == 0 || window_name == 0 ) CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); window = icvFindWindowByName( window_name ); if( window ) trackbar = icvFindTrackbarByName( window, trackbar_name ); if( trackbar ) { if( pos < 0 ) pos = 0; if( pos > trackbar->maxval ) pos = trackbar->maxval; } CV_LOCK_MUTEX(); gtk_range_set_value( GTK_RANGE(trackbar->widget), pos ); CV_UNLOCK_MUTEX(); __END__; } CV_IMPL void* cvGetWindowHandle( const char* window_name ) { void* widget = 0; CV_FUNCNAME( "cvGetWindowHandle" ); __BEGIN__; CvWindow* window; if( window_name == 0 ) CV_ERROR( CV_StsNullPtr, "NULL window name" ); window = icvFindWindowByName( window_name ); if( window ) widget = (void*)window->widget; __END__; return widget; } CV_IMPL const char* cvGetWindowName( void* window_handle ) { const char* window_name = ""; CV_FUNCNAME( "cvGetWindowName" ); __BEGIN__; CvWindow* window; if( window_handle == 0 ) CV_ERROR( CV_StsNullPtr, "NULL window" ); window = icvWindowByWidget( (GtkWidget*)window_handle ); if( window ) window_name = window->name; __END__; return window_name; } static gboolean icvOnKeyPress( GtkWidget * /*widget*/, GdkEventKey* event, gpointer /*user_data*/ ) { int code = 0; switch( event->keyval ) { case GDK_Escape: code = 27; break; case GDK_Return: case GDK_Linefeed: code = '\n'; break; case GDK_Tab: code = '\t'; break; default: code = event->keyval; } code |= event->state << 16; #ifdef HAVE_GTHREAD if(thread_started) g_mutex_lock(last_key_mutex); #endif last_key = code; #ifdef HAVE_GTHREAD if(thread_started){ // signal any waiting threads g_cond_broadcast(cond_have_key); g_mutex_unlock(last_key_mutex); } #endif return FALSE; } static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ) { int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget))); CvTrackbar* trackbar = (CvTrackbar*)user_data; if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL && trackbar->widget == widget ) { trackbar->pos = pos; if( trackbar->data ) *trackbar->data = pos; if( trackbar->notify2 ) trackbar->notify2(pos, trackbar->userdata); else if( trackbar->notify ) trackbar->notify(pos); } } static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data ) { CvWindow* window = (CvWindow*)user_data; if( window->signature == CV_WINDOW_MAGIC_VAL && window->frame == widget ) { icvDeleteWindow(window); } return TRUE; } static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ) { // TODO move this logic to CvImageWidget CvWindow* window = (CvWindow*)user_data; CvPoint2D32f pt32f = {-1., -1.}; CvPoint pt = {-1,-1}; int cv_event = -1, state = 0; CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); if( window->signature != CV_WINDOW_MAGIC_VAL || window->widget != widget || !window->widget || !window->on_mouse || !image_widget->original_image) return FALSE; if( event->type == GDK_MOTION_NOTIFY ) { GdkEventMotion* event_motion = (GdkEventMotion*)event; cv_event = CV_EVENT_MOUSEMOVE; pt32f.x = cvRound(event_motion->x); pt32f.y = cvRound(event_motion->y); state = event_motion->state; } else if( event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE || event->type == GDK_2BUTTON_PRESS ) { GdkEventButton* event_button = (GdkEventButton*)event; pt32f.x = cvRound(event_button->x); pt32f.y = cvRound(event_button->y); if( event_button->type == GDK_BUTTON_PRESS ) { cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN : event_button->button == 2 ? CV_EVENT_MBUTTONDOWN : event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0; } else if( event_button->type == GDK_BUTTON_RELEASE ) { cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP : event_button->button == 2 ? CV_EVENT_MBUTTONUP : event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0; } else if( event_button->type == GDK_2BUTTON_PRESS ) { cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK : event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK : event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0; } state = event_button->state; } if( cv_event >= 0 ){ // scale point if image is scaled if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image && image_widget->scaled_image ){ // image origin is not necessarily at (0,0) int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; pt.x = cvRound( ((pt32f.x-x0)*image_widget->original_image->cols)/ image_widget->scaled_image->cols ); pt.y = cvRound( ((pt32f.y-y0)*image_widget->original_image->rows)/ image_widget->scaled_image->rows ); } else{ pt = cvPointFrom32f( pt32f ); } if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) && (unsigned)pt.y < (unsigned)(image_widget->original_image->height) ) { int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) | (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) | (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) | (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) | (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) | (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0); window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param ); } } return FALSE; } static gboolean icvAlarm( gpointer user_data ) { *(int*)user_data = 1; return FALSE; } CV_IMPL int cvWaitKey( int delay ) { #ifdef HAVE_GTHREAD if(thread_started && g_thread_self()!=window_thread){ gboolean expired; int my_last_key; // wait for signal or timeout if delay > 0 if(delay>0){ GTimeVal timer; g_get_current_time(&timer); g_time_val_add(&timer, delay*1000); expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer); } else{ g_cond_wait(cond_have_key, last_key_mutex); expired=false; } my_last_key = last_key; g_mutex_unlock(last_key_mutex); if(expired || hg_windows==0){ return -1; } return my_last_key; } else{ #endif int expired = 0; guint timer = 0; if( delay > 0 ) timer = g_timeout_add( delay, icvAlarm, &expired ); last_key = -1; while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 ) ; if( delay > 0 && !expired ) g_source_remove(timer); #ifdef HAVE_GTHREAD } #endif return last_key; } #endif // HAVE_GTK #endif // WIN32 /* End of file. */