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