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"
46 #if defined (HAVE_GTK)
49 #include <gdk/gdkkeysyms.h>
50 #include <gdk-pixbuf/gdk-pixbuf.h>
53 #if (GTK_MAJOR_VERSION == 3)
54 #define GTK_VERSION3 1
55 #endif //GTK_MAJOR_VERSION >= 3
56 #if (GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4))
57 #define GTK_VERSION3_4 1
61 #include <gtk/gtkgl.h>
66 #include <opencv2/core/utils/logger.hpp>
67 #include "opencv2/imgproc.hpp"
72 #define BIT_ALLIN(x,y) ( ((x)&(y)) == (y) )
75 #define BIT_MAP(x,y,z) ( ((x)&(y)) ? (z) : 0 )
78 // TODO Fix the initial window size when flags=0. Right now the initial window is by default
79 // 320x240 size. A better default would be actual size of the image. Problem
80 // is determining desired window size with trackbars while still allowing resizing.
82 // Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio
83 // in totem/src/backend/bacon-video-widget-xine.c
85 ////////////////////////////////////////////////////////////
86 // CvImageWidget GTK Widget Public API
87 ////////////////////////////////////////////////////////////
88 typedef struct _CvImageWidget CvImageWidget;
89 typedef struct _CvImageWidgetClass CvImageWidgetClass;
91 struct _CvImageWidget {
93 CvMat * original_image;
98 struct _CvImageWidgetClass
100 GtkWidgetClass parent_class;
104 /** Allocate new image viewer widget */
105 GtkWidget* cvImageWidgetNew (int flags);
107 /** Set the image to display in the widget */
108 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr);
110 // standard GTK object macros
111 #define CV_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, cvImageWidget_get_type (), CvImageWidget)
112 #define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass)
113 #define CV_IS_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, cvImageWidget_get_type ())
115 /////////////////////////////////////////////////////////////////////////////
116 // Private API ////////////////////////////////////////////////////////
117 /////////////////////////////////////////////////////////////////////////////
118 GType cvImageWidget_get_type (void);
120 static GtkWidgetClass * parent_class = NULL;
122 // flag to help size initial window
123 #define CV_WINDOW_NO_IMAGE 2
125 void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){
129 //printf("cvImageWidgetSetImage\n");
131 if( CV_IS_IMAGE_HDR( arr ))
132 origin = ((IplImage*)arr)->origin;
134 mat = cvGetMat(arr, &stub);
136 if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){
137 cvReleaseMat( &widget->original_image );
139 if(!widget->original_image){
140 widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 );
141 gtk_widget_queue_resize( GTK_WIDGET( widget ) );
143 cvConvertImage( mat, widget->original_image,
144 (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
145 if(widget->scaled_image){
146 cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA );
149 // window does not refresh without this
150 gtk_widget_queue_draw( GTK_WIDGET(widget) );
154 cvImageWidgetNew (int flags)
156 CvImageWidget *image_widget;
158 image_widget = CV_IMAGE_WIDGET( gtk_widget_new (cvImageWidget_get_type (), NULL) );
159 image_widget->original_image = 0;
160 image_widget->scaled_image = 0;
161 image_widget->flags = flags | CV_WINDOW_NO_IMAGE;
163 return GTK_WIDGET (image_widget);
167 cvImageWidget_realize (GtkWidget *widget)
169 GdkWindowAttr attributes;
170 gint attributes_mask;
172 #if defined(GTK_VERSION3)
173 GtkAllocation allocation;
174 gtk_widget_get_allocation(widget, &allocation);
175 #endif //GTK_VERSION3
177 //printf("cvImageWidget_realize\n");
178 g_return_if_fail (widget != NULL);
179 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
181 gtk_widget_set_realized(widget, TRUE);
183 #if defined(GTK_VERSION3)
184 attributes.x = allocation.x;
185 attributes.y = allocation.y;
186 attributes.width = allocation.width;
187 attributes.height = allocation.height;
189 attributes.x = widget->allocation.x;
190 attributes.y = widget->allocation.y;
191 attributes.width = widget->allocation.width;
192 attributes.height = widget->allocation.height;
193 #endif //GTK_VERSION3
195 attributes.wclass = GDK_INPUT_OUTPUT;
196 attributes.window_type = GDK_WINDOW_CHILD;
197 attributes.event_mask = gtk_widget_get_events (widget) |
198 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
199 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
200 attributes.visual = gtk_widget_get_visual (widget);
202 #if defined(GTK_VERSION3)
203 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
204 gtk_widget_set_window(
207 gtk_widget_get_parent_window(widget),
213 gtk_widget_set_style(
216 gtk_widget_get_style(widget),
217 gtk_widget_get_window(widget)
221 gdk_window_set_user_data (
222 gtk_widget_get_window(widget),
226 gtk_style_set_background (
227 gtk_widget_get_style(widget),
228 gtk_widget_get_window(widget),
232 // The following lines are included to prevent breaking
233 // compatibility with older Gtk2 (<gtk+-2.18) libraries.
234 attributes.colormap = gtk_widget_get_colormap (widget);
235 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
236 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
238 widget->style = gtk_style_attach (widget->style, widget->window);
239 gdk_window_set_user_data (widget->window, widget);
241 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
242 #endif // GTK_VERSION3
245 static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){
246 float aspect = (float)im_width/(float)im_height;
247 float max_aspect = (float)max_width/(float)max_height;
248 if(aspect > max_aspect){
249 return cvSize( max_width, cvRound(max_width/aspect) );
251 return cvSize( cvRound(max_height*aspect), max_height );
254 #if defined (GTK_VERSION3)
256 cvImageWidget_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
258 g_return_if_fail (widget != NULL);
259 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
260 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
262 if(image_widget->original_image != NULL) {
263 *minimal_width = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ?
264 gdk_window_get_width(gtk_widget_get_window(widget)) : image_widget->original_image->cols;
267 *minimal_width = 320;
270 if(image_widget->scaled_image != NULL) {
271 *natural_width = *minimal_width < image_widget->scaled_image->cols ?
272 image_widget->scaled_image->cols : *minimal_width;
275 *natural_width = *minimal_width;
280 cvImageWidget_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
282 g_return_if_fail (widget != NULL);
283 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
284 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
286 if(image_widget->original_image != NULL) {
287 *minimal_height = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ?
288 gdk_window_get_height(gtk_widget_get_window(widget)) : image_widget->original_image->rows;
291 *minimal_height = 240;
294 if(image_widget->scaled_image != NULL) {
295 *natural_height = *minimal_height < image_widget->scaled_image->rows ?
296 image_widget->scaled_image->rows : *minimal_height;
299 *natural_height = *minimal_height;
305 cvImageWidget_size_request (GtkWidget *widget,
306 GtkRequisition *requisition)
308 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
310 //printf("cvImageWidget_size_request ");
311 // the case the first time cvShowImage called or when AUTOSIZE
312 if( image_widget->original_image &&
313 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
314 (image_widget->flags & CV_WINDOW_NO_IMAGE)))
316 //printf("original ");
317 requisition->width = image_widget->original_image->cols;
318 requisition->height = image_widget->original_image->rows;
321 else if(image_widget->scaled_image){
323 requisition->width = image_widget->scaled_image->cols;
324 requisition->height = image_widget->scaled_image->rows;
326 // the case before cvShowImage called
328 //printf("default ");
329 requisition->width = 320;
330 requisition->height = 240;
332 //printf("%d %d\n",requisition->width, requisition->height);
334 #endif //GTK_VERSION3
336 static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){
337 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
339 //printf("cvImageWidget_set_size %d %d\n", max_width, max_height);
341 // don't allow to set the size
342 if(image_widget->flags & CV_WINDOW_AUTOSIZE) return;
343 if(!image_widget->original_image) return;
345 CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols,
346 image_widget->original_image->rows, max_width, max_height );
348 if( image_widget->scaled_image &&
349 ( image_widget->scaled_image->cols != scaled_image_size.width ||
350 image_widget->scaled_image->rows != scaled_image_size.height ))
352 cvReleaseMat( &image_widget->scaled_image );
354 if( !image_widget->scaled_image ){
355 image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 );
359 assert( image_widget->scaled_image );
363 cvImageWidget_size_allocate (GtkWidget *widget,
364 GtkAllocation *allocation)
366 CvImageWidget *image_widget;
368 //printf("cvImageWidget_size_allocate\n");
369 g_return_if_fail (widget != NULL);
370 g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));
371 g_return_if_fail (allocation != NULL);
373 #if defined (GTK_VERSION3)
374 gtk_widget_set_allocation(widget, allocation);
376 widget->allocation = *allocation;
377 #endif //GTK_VERSION3
378 image_widget = CV_IMAGE_WIDGET (widget);
381 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){
382 // (re) allocated scaled image
383 if( image_widget->flags & CV_WINDOW_NO_IMAGE ){
384 cvImageWidget_set_size( widget, image_widget->original_image->cols,
385 image_widget->original_image->rows);
388 cvImageWidget_set_size( widget, allocation->width, allocation->height );
390 cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA );
393 if (gtk_widget_get_realized (widget))
395 image_widget = CV_IMAGE_WIDGET (widget);
397 if( image_widget->original_image &&
398 ((image_widget->flags & CV_WINDOW_AUTOSIZE) ||
399 (image_widget->flags & CV_WINDOW_NO_IMAGE)) )
401 #if defined (GTK_VERSION3)
402 allocation->width = image_widget->original_image->cols;
403 allocation->height = image_widget->original_image->rows;
404 gtk_widget_set_allocation(widget, allocation);
406 widget->allocation.width = image_widget->original_image->cols;
407 widget->allocation.height = image_widget->original_image->rows;
408 #endif //GTK_VERSION3
409 gdk_window_move_resize( gtk_widget_get_window(widget),
410 allocation->x, allocation->y,
411 image_widget->original_image->cols, image_widget->original_image->rows );
412 if(image_widget->flags & CV_WINDOW_NO_IMAGE){
413 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
414 gtk_widget_queue_resize( GTK_WIDGET(widget) );
418 gdk_window_move_resize (gtk_widget_get_window(widget),
419 allocation->x, allocation->y,
420 allocation->width, allocation->height );
425 #if defined (GTK_VERSION3)
427 cvImageWidget_destroy (GtkWidget *object)
430 cvImageWidget_destroy (GtkObject *object)
431 #endif //GTK_VERSION3
433 CvImageWidget *image_widget;
435 g_return_if_fail (object != NULL);
436 g_return_if_fail (CV_IS_IMAGE_WIDGET (object));
438 image_widget = CV_IMAGE_WIDGET (object);
440 cvReleaseMat( &image_widget->scaled_image );
441 cvReleaseMat( &image_widget->original_image );
443 #if defined (GTK_VERSION3)
444 if (GTK_WIDGET_CLASS (parent_class)->destroy)
445 (* GTK_WIDGET_CLASS (parent_class)->destroy) (object);
447 if (GTK_OBJECT_CLASS (parent_class)->destroy)
448 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
449 #endif //GTK_VERSION3
452 static void cvImageWidget_class_init (gpointer g_class, gpointer /*class_data*/)
454 CvImageWidgetClass* klass = (CvImageWidgetClass*)g_class;
455 #if defined (GTK_VERSION3)
456 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
458 GtkObjectClass *object_class;
459 GtkWidgetClass *widget_class;
461 object_class = (GtkObjectClass*) klass;
462 widget_class = (GtkWidgetClass*) klass;
463 #endif //GTK_VERSION3
465 parent_class = GTK_WIDGET_CLASS( g_type_class_peek (gtk_widget_get_type ()) );
467 #if defined (GTK_VERSION3)
468 widget_class->destroy = cvImageWidget_destroy;
469 widget_class->get_preferred_width = cvImageWidget_get_preferred_width;
470 widget_class->get_preferred_height = cvImageWidget_get_preferred_height;
472 object_class->destroy = cvImageWidget_destroy;
473 widget_class->size_request = cvImageWidget_size_request;
474 #endif //GTK_VERSION3
476 widget_class->realize = cvImageWidget_realize;
477 widget_class->size_allocate = cvImageWidget_size_allocate;
478 widget_class->button_press_event = NULL;
479 widget_class->button_release_event = NULL;
480 widget_class->motion_notify_event = NULL;
484 cvImageWidget_init(GTypeInstance* instance, gpointer /*g_class*/)
486 CvImageWidget* image_widget = (CvImageWidget*)instance;
487 image_widget->original_image=0;
488 image_widget->scaled_image=0;
489 image_widget->flags=0;
492 GType cvImageWidget_get_type (void){
493 static GType image_type = 0;
497 image_type = g_type_register_static_simple(
499 (gchar*) "CvImageWidget",
500 sizeof(CvImageWidgetClass),
501 cvImageWidget_class_init,
502 sizeof(CvImageWidget),
510 /////////////////////////////////////////////////////////////////////////////
512 /////////////////////////////////////////////////////////////////////////////
518 CvUIBase(int signature_) : signature(signature_) { }
523 struct CvTrackbar : CvUIBase
525 CvTrackbar(const char* trackbar_name) :
526 CvUIBase(CV_TRACKBAR_MAGIC_VAL),
527 widget(NULL), name(trackbar_name),
528 parent(NULL), data(NULL),
529 pos(0), maxval(0), minval(0),
530 notify(NULL), notify2(NULL), userdata(NULL)
536 // destroyed by parent window
546 CvTrackbarCallback notify;
547 CvTrackbarCallback2 notify2;
552 struct CvWindow : CvUIBase
554 CvWindow(const char* window_name) :
555 CvUIBase(CV_WINDOW_MAGIC_VAL),
556 widget(NULL), frame(NULL), paned(NULL), name(window_name),
557 last_key(0), flags(0), status(0),
558 on_mouse(NULL), on_mouse_param(NULL)
560 ,useGl(false), glDrawCallback(NULL), glDrawData(NULL)
574 int status;//0 normal, 1 fullscreen (YV)
576 CvMouseCallback on_mouse;
577 void* on_mouse_param;
579 std::vector< Ptr<CvTrackbar> > trackbars;
584 CvOpenGlDrawCallback glDrawCallback;
590 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
591 static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
592 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
593 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
596 int thread_started=0;
597 static gpointer icvWindowThreadLoop(gpointer data);
598 GMutex* last_key_mutex = NULL;
599 GCond* cond_have_key = NULL;
600 GMutex* window_mutex = NULL;
601 GThread* window_thread = NULL;
604 static int last_key = -1;
605 static std::vector< Ptr<CvWindow> > g_windows;
607 CV_IMPL int cvInitSystem( int argc, char** argv )
609 static int wasInitialized = 0;
611 // check initialization status
612 if( !wasInitialized )
614 gtk_init( &argc, &argv );
615 setlocale(LC_NUMERIC,"C");
618 gtk_gl_init(&argc, &argv);
627 CV_IMPL int cvStartWindowThread(){
629 cvInitSystem(0,NULL);
630 if (!thread_started) {
631 if (!g_thread_supported ()) {
632 /* the GThread system wasn't inited, so init it */
636 // this mutex protects the window resources
637 window_mutex = g_mutex_new();
639 // protects the 'last key pressed' variable
640 last_key_mutex = g_mutex_new();
642 // conditional that indicates a key has been pressed
643 cond_have_key = g_cond_new();
645 #if !GLIB_CHECK_VERSION(2, 32, 0)
646 // this is the window update thread
647 window_thread = g_thread_create(icvWindowThreadLoop,
650 window_thread = g_thread_new("OpenCV window update", icvWindowThreadLoop, NULL);
653 thread_started = window_thread!=NULL;
654 return thread_started;
661 gpointer icvWindowThreadLoop(gpointer /*data*/)
664 g_mutex_lock(window_mutex);
665 gtk_main_iteration_do(FALSE);
666 g_mutex_unlock(window_mutex);
680 GMutexLock(GMutex* mutex) : mutex_(mutex) { if (mutex_) g_mutex_lock(mutex_); }
681 ~GMutexLock() { if (mutex_) g_mutex_unlock(mutex_); mutex_ = NULL; }
684 #define CV_LOCK_MUTEX() GMutexLock lock(window_mutex);
687 #define CV_LOCK_MUTEX()
690 static CvWindow* icvFindWindowByName( const char* name )
692 for(size_t i = 0; i < g_windows.size(); ++i)
694 CvWindow* window = g_windows[i].get();
695 if (window->name == name)
701 static CvWindow* icvWindowByWidget( GtkWidget* widget )
703 for (size_t i = 0; i < g_windows.size(); ++i)
705 CvWindow* window = g_windows[i].get();
706 if (window->widget == widget || window->frame == widget || window->paned == widget)
712 CvRect cvGetWindowRect_GTK(const char* name)
714 CV_Assert(name && "NULL name string");
717 CvWindow* window = icvFindWindowByName(name);
719 CV_Error( CV_StsNullPtr, "NULL window" );
724 gtk_widget_translate_coordinates(window->widget, gtk_widget_get_toplevel(window->widget), 0, 0, &wx, &wy);
725 return cvRect(wx, wy, window->widget->allocation.width, window->widget->allocation.height);
729 CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
730 gtk_widget_translate_coordinates(&image_widget->widget, gtk_widget_get_toplevel(&image_widget->widget), 0, 0, &wx, &wy);
731 if (image_widget->scaled_image) {
732 #if defined (GTK_VERSION3)
733 return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(window->widget)),
734 MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(window->widget)));
736 return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, window->widget->allocation.width),
737 MIN(image_widget->scaled_image->rows, window->widget->allocation.height));
738 #endif //GTK_VERSION3
739 } else if (image_widget->original_image) {
740 #if defined (GTK_VERSION3)
741 return cvRect(wx, wy, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(window->widget)),
742 MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(window->widget)));
744 return cvRect(wx, wy, MIN(image_widget->original_image->cols, window->widget->allocation.width),
745 MIN(image_widget->original_image->rows, window->widget->allocation.height));
746 #endif //GTK_VERSION3
749 return cvRect(-1, -1, -1, -1);
752 double cvGetModeWindow_GTK(const char* name)//YV
754 CV_Assert(name && "NULL name string");
757 CvWindow* window = icvFindWindowByName(name);
759 CV_Error( CV_StsNullPtr, "NULL window" );
761 double result = window->status;
766 void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
768 CV_Assert(name && "NULL name string");
772 CvWindow* window = icvFindWindowByName(name);
774 CV_Error( CV_StsNullPtr, "NULL window" );
776 if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
779 //so easy to do fullscreen here, Linux rocks !
781 if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
783 gtk_window_unfullscreen(GTK_WINDOW(window->frame));
784 window->status=CV_WINDOW_NORMAL;
788 if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
790 gtk_window_fullscreen(GTK_WINDOW(window->frame));
791 window->status=CV_WINDOW_FULLSCREEN;
796 void cv::setWindowTitle(const String& winname, const String& title)
800 CvWindow* window = icvFindWindowByName(winname.c_str());
804 namedWindow(winname);
805 window = icvFindWindowByName(winname.c_str());
809 gtk_window_set_title(GTK_WINDOW(window->frame), title.c_str());
812 double cvGetPropWindowAutoSize_GTK(const char* name)
814 CV_Assert(name && "NULL name string");
818 CvWindow* window = icvFindWindowByName(name);
820 return -1; // keep silence here
822 double result = window->flags & CV_WINDOW_AUTOSIZE;
826 double cvGetRatioWindow_GTK(const char* name)
828 CV_Assert(name && "NULL name string");
832 CvWindow* window = icvFindWindowByName(name);
834 return -1; // keep silence here
836 #if defined (GTK_VERSION3)
837 double result = static_cast<double>(
838 gtk_widget_get_allocated_width(window->widget)) / gtk_widget_get_allocated_height(window->widget);
840 double result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
841 #endif // GTK_VERSION3
845 double cvGetOpenGlProp_GTK(const char* name)
848 CV_Assert(name && "NULL name string");
852 CvWindow* window = icvFindWindowByName(name);
854 return -1; // keep silence here
856 double result = window->useGl;
871 void createGlContext(CvWindow* window)
873 GdkGLConfig* glconfig;
875 // Try double-buffered visual
876 glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
878 CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
880 // Set OpenGL-capability to the widget
881 if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))
882 CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
884 window->useGl = true;
887 void drawGl(CvWindow* window)
889 GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
890 GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
892 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
893 CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
895 glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);
897 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
899 if (window->glDrawCallback)
900 window->glDrawCallback(window->glDrawData);
902 if (gdk_gl_drawable_is_double_buffered (gldrawable))
903 gdk_gl_drawable_swap_buffers(gldrawable);
907 gdk_gl_drawable_gl_end(gldrawable);
911 #endif // HAVE_OPENGL
913 #if defined (GTK_VERSION3)
914 static gboolean cvImageWidget_draw(GtkWidget* widget, cairo_t *cr, gpointer data)
917 CvWindow* window = (CvWindow*)data;
928 CvImageWidget *image_widget = NULL;
929 GdkPixbuf *pixbuf = NULL;
931 g_return_val_if_fail (widget != NULL, FALSE);
932 g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
934 image_widget = CV_IMAGE_WIDGET (widget);
936 if( image_widget->scaled_image ){
937 // center image in available region
938 #if defined (GTK_VERSION3)
939 int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2;
940 int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2;
942 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
943 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
944 #endif //GTK_VERSION3
946 #if defined (GTK_VERSION3)
947 pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,
948 8, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(widget)),
949 MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(widget)),
950 image_widget->scaled_image->step, NULL, NULL);
952 pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,
953 8, MIN(image_widget->scaled_image->cols, widget->allocation.width),
954 MIN(image_widget->scaled_image->rows, widget->allocation.height),
955 image_widget->scaled_image->step, NULL, NULL);
956 #endif //GTK_VERSION3
958 gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0);
960 else if( image_widget->original_image ){
961 #if defined (GTK_VERSION3)
962 pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,
963 8, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(widget)),
964 MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(widget)),
965 image_widget->original_image->step, NULL, NULL);
967 pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,
968 8, MIN(image_widget->original_image->cols, widget->allocation.width),
969 MIN(image_widget->original_image->rows, widget->allocation.height),
970 image_widget->original_image->step, NULL, NULL);
971 #endif //GTK_VERSION3
972 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
977 g_object_unref(pixbuf);
982 static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
985 CvWindow* window = (CvWindow*)data;
996 CvImageWidget *image_widget = NULL;
998 GdkPixbuf *pixbuf = NULL;
1000 g_return_val_if_fail (widget != NULL, FALSE);
1001 g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
1002 g_return_val_if_fail (event != NULL, FALSE);
1004 if (event->count > 0)
1007 cr = gdk_cairo_create(widget->window);
1008 image_widget = CV_IMAGE_WIDGET (widget);
1010 if( image_widget->scaled_image ){
1011 // center image in available region
1012 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1013 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1015 pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,
1016 8, MIN(image_widget->scaled_image->cols, widget->allocation.width),
1017 MIN(image_widget->scaled_image->rows, widget->allocation.height),
1018 image_widget->scaled_image->step, NULL, NULL);
1020 gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0);
1022 else if( image_widget->original_image ){
1023 pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,
1024 8, MIN(image_widget->original_image->cols, widget->allocation.width),
1025 MIN(image_widget->original_image->rows, widget->allocation.height),
1026 image_widget->original_image->step, NULL, NULL);
1027 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
1032 g_object_unref(pixbuf);
1036 #endif //GTK_VERSION3
1038 CV_IMPL int cvNamedWindow( const char* name, int flags )
1040 cvInitSystem(name ? 1 : 0,(char**)&name);
1041 CV_Assert(name && "NULL name string");
1045 // Check the name in the storage
1046 if (icvFindWindowByName(name))
1051 Ptr<CvWindow> window = makePtr<CvWindow>(name);
1052 window->flags = flags;
1053 window->status = CV_WINDOW_NORMAL;//YV
1055 window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
1057 window->paned = gtk_vbox_new( FALSE, 0 );
1058 window->widget = cvImageWidgetNew( flags );
1059 gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
1060 gtk_widget_show( window->widget );
1061 gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
1062 gtk_widget_show( window->paned );
1065 if (flags & CV_WINDOW_OPENGL)
1066 CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
1068 if (flags & CV_WINDOW_OPENGL)
1069 createGlContext(window);
1071 window->glDrawCallback = 0;
1072 window->glDrawData = 0;
1076 // configure event handlers
1077 // TODO -- move this to CvImageWidget ?
1078 g_signal_connect( window->frame, "key-press-event",
1079 G_CALLBACK(icvOnKeyPress), window );
1080 g_signal_connect( window->widget, "button-press-event",
1081 G_CALLBACK(icvOnMouse), window );
1082 g_signal_connect( window->widget, "button-release-event",
1083 G_CALLBACK(icvOnMouse), window );
1084 g_signal_connect( window->widget, "motion-notify-event",
1085 G_CALLBACK(icvOnMouse), window );
1086 g_signal_connect( window->widget, "scroll-event",
1087 G_CALLBACK(icvOnMouse), window );
1088 g_signal_connect( window->frame, "delete-event",
1089 G_CALLBACK(icvOnClose), window );
1090 #if defined(GTK_VERSION3)
1091 g_signal_connect( window->widget, "draw",
1092 G_CALLBACK(cvImageWidget_draw), window );
1094 g_signal_connect( window->widget, "expose-event",
1095 G_CALLBACK(cvImageWidget_expose), window );
1096 #endif //GTK_VERSION3
1099 #if defined(GTK_VERSION3_4)
1100 gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK) ;
1102 gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK) ;
1103 #endif //GTK_VERSION3_4
1105 gtk_widget_show( window->frame );
1106 gtk_window_set_title( GTK_WINDOW(window->frame), name );
1108 g_windows.push_back(window);
1110 bool b_nautosize = ((flags & CV_WINDOW_AUTOSIZE) == 0);
1111 gtk_window_set_resizable( GTK_WINDOW(window->frame), b_nautosize );
1113 // allow window to be resized
1115 GdkGeometry geometry;
1116 geometry.min_width = 50;
1117 geometry.min_height = 50;
1118 gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
1119 &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
1124 cvSetOpenGlContext(name);
1133 CV_IMPL void cvSetOpenGlContext(const char* name)
1135 GdkGLContext* glcontext;
1136 GdkGLDrawable* gldrawable;
1138 CV_Assert(name && "NULL name string");
1142 CvWindow* window = icvFindWindowByName(name);
1144 CV_Error( CV_StsNullPtr, "NULL window" );
1147 CV_Error( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
1149 glcontext = gtk_widget_get_gl_context(window->widget);
1150 gldrawable = gtk_widget_get_gl_drawable(window->widget);
1152 if (!gdk_gl_drawable_make_current(gldrawable, glcontext))
1153 CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
1156 CV_IMPL void cvUpdateWindow(const char* name)
1158 CV_Assert(name && "NULL name string");
1162 CvWindow* window = icvFindWindowByName(name);
1166 // window does not refresh without this
1167 gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
1170 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
1172 CV_Assert(name && "NULL name string");
1176 CvWindow* window = icvFindWindowByName(name);
1181 CV_Error( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
1183 window->glDrawCallback = callback;
1184 window->glDrawData = userdata;
1187 #endif // HAVE_OPENGL
1191 CvWindow::~CvWindow()
1193 gtk_widget_destroy(frame);
1196 static void checkLastWindow()
1198 // if last window...
1199 if (g_windows.empty())
1202 if( thread_started )
1204 // send key press signal to jump out of any waiting cvWaitKey's
1205 g_cond_broadcast( cond_have_key );
1210 // Some GTK+ modules (like the Unity module) use GDBusConnection,
1211 // which has a habit of postponing cleanup by performing it via
1212 // idle sources added to the main loop. Since this was the last window,
1213 // we can assume that no event processing is going to happen in the
1214 // nearest future, so we should force that cleanup (by handling all pending
1215 // events) while we still have the chance.
1216 // This is not needed if thread_started is true, because the background
1217 // thread will process events continuously.
1218 while( gtk_events_pending() )
1219 gtk_main_iteration();
1226 static void icvDeleteWindow( CvWindow* window )
1229 for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin();
1230 i != g_windows.end(); ++i)
1232 if (i->get() == window)
1239 CV_Assert(found && "Can't destroy non-registered window");
1244 CV_IMPL void cvDestroyWindow( const char* name )
1246 CV_Assert(name && "NULL name string");
1251 for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin();
1252 i != g_windows.end(); ++i)
1254 if (i->get()->name == name)
1261 CV_Assert(found && "Can't destroy non-registered window");
1268 cvDestroyAllWindows( void )
1276 // CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
1277 // CvSize window_size;
1278 // GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
1279 // gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
1280 // &window_size.width, &window_size.height );
1282 // window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
1283 // window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
1285 // return window_size;
1289 cvShowImage( const char* name, const CvArr* arr )
1291 CV_Assert(name && "NULL name string");
1295 CvWindow* window = icvFindWindowByName(name);
1298 cvNamedWindow(name, 1);
1299 window = icvFindWindowByName(name);
1308 cv::imshow(name, cv::cvarrToMat(arr));
1313 CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
1314 cvImageWidgetSetImage( image_widget, arr );
1318 CV_IMPL void cvResizeWindow(const char* name, int width, int height )
1320 CV_Assert(name && "NULL name string");
1324 CvWindow* window = icvFindWindowByName(name);
1328 CvImageWidget* image_widget = CV_IMAGE_WIDGET( window->widget );
1329 //if(image_widget->flags & CV_WINDOW_AUTOSIZE)
1332 gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
1333 gtk_window_resize( GTK_WINDOW(window->frame), width, height );
1335 // disable initial resize since presumably user wants to keep
1337 image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
1341 CV_IMPL void cvMoveWindow( const char* name, int x, int y )
1343 CV_Assert(name && "NULL name string");
1347 CvWindow* window = icvFindWindowByName(name);
1351 gtk_window_move( GTK_WINDOW(window->frame), x, y );
1356 icvFindTrackbarByName( const CvWindow* window, const char* name )
1358 for (size_t i = 0; i < window->trackbars.size(); ++i)
1360 CvTrackbar* trackbar = window->trackbars[i].get();
1361 if (trackbar->name == name)
1368 icvCreateTrackbar( const char* trackbar_name, const char* window_name,
1369 int* val, int count, CvTrackbarCallback on_notify,
1370 CvTrackbarCallback2 on_notify2, void* userdata )
1372 CV_Assert(window_name && "NULL window name");
1373 CV_Assert(trackbar_name && "NULL trackbar name");
1376 CV_Error( CV_StsOutOfRange, "Bad trackbar maximal value" );
1380 CvWindow* window = icvFindWindowByName(window_name);
1384 CvTrackbar* trackbar = icvFindTrackbarByName(window, trackbar_name);
1387 Ptr<CvTrackbar> trackbar_ = makePtr<CvTrackbar>(trackbar_name);
1388 trackbar = trackbar_.get();
1389 trackbar->parent = window;
1390 window->trackbars.push_back(trackbar_);
1392 GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
1393 GtkWidget* hscale_label = gtk_label_new( trackbar_name );
1394 GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
1395 gtk_scale_set_digits( GTK_SCALE(hscale), 0 );
1396 //gtk_scale_set_value_pos( hscale, GTK_POS_TOP );
1397 gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );
1399 trackbar->widget = hscale;
1400 gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );
1401 gtk_widget_show( hscale_label );
1402 gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );
1403 gtk_widget_show( hscale );
1404 gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );
1405 gtk_widget_show( hscale_box );
1415 gtk_range_set_value( GTK_RANGE(trackbar->widget), value );
1416 trackbar->pos = value;
1417 trackbar->data = val;
1420 trackbar->maxval = count;
1421 trackbar->notify = on_notify;
1422 trackbar->notify2 = on_notify2;
1423 trackbar->userdata = userdata;
1424 g_signal_connect( trackbar->widget, "value-changed",
1425 G_CALLBACK(icvOnTrackbar), trackbar );
1427 // queue a widget resize to trigger a window resize to
1428 // compensate for the addition of trackbars
1429 gtk_widget_queue_resize( GTK_WIDGET(window->widget) );
1436 cvCreateTrackbar( const char* trackbar_name, const char* window_name,
1437 int* val, int count, CvTrackbarCallback on_notify )
1439 return icvCreateTrackbar(trackbar_name, window_name, val, count,
1445 cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
1446 int* val, int count, CvTrackbarCallback2 on_notify2,
1449 return icvCreateTrackbar(trackbar_name, window_name, val, count,
1450 0, on_notify2, userdata);
1455 cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
1457 CV_Assert(window_name && "NULL window name");
1461 CvWindow* window = icvFindWindowByName(window_name);
1465 window->on_mouse = on_mouse;
1466 window->on_mouse_param = param;
1470 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
1472 CV_Assert(window_name && "NULL window name");
1473 CV_Assert(trackbar_name && "NULL trackbar name");
1477 CvWindow* window = icvFindWindowByName(window_name);
1481 CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);
1485 return trackbar->pos;
1489 CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
1491 CV_Assert(window_name && "NULL window name");
1492 CV_Assert(trackbar_name && "NULL trackbar name");
1496 CvWindow* window = icvFindWindowByName(window_name);
1500 CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);
1503 if( pos < trackbar->minval )
1504 pos = trackbar->minval;
1506 if( pos > trackbar->maxval )
1507 pos = trackbar->maxval;
1511 CV_Error( CV_StsNullPtr, "No trackbar found" );
1514 gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
1518 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
1520 CV_Assert(window_name && "NULL window name");
1521 CV_Assert(trackbar_name && "NULL trackbar name");
1525 CvWindow* window = icvFindWindowByName(window_name);
1529 CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);
1533 trackbar->maxval = maxval;
1534 if (trackbar->maxval >= trackbar->minval)
1535 gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval);
1539 CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
1541 CV_Assert(window_name && "NULL window name");
1542 CV_Assert(trackbar_name && "NULL trackbar name");
1546 CvWindow* window = icvFindWindowByName(window_name);
1550 CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);
1554 trackbar->minval = minval;
1555 if (trackbar->maxval >= trackbar->minval)
1556 gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval);
1560 CV_IMPL void* cvGetWindowHandle( const char* window_name )
1562 CV_Assert(window_name && "NULL window name");
1566 CvWindow* window = icvFindWindowByName(window_name);
1570 return (void*)window->widget;
1574 CV_IMPL const char* cvGetWindowName( void* window_handle )
1576 CV_Assert(window_handle && "NULL window handle");
1580 CvWindow* window = icvWindowByWidget( (GtkWidget*)window_handle );
1582 return window->name.c_str();
1584 return ""; // FIXME: NULL?
1587 static GtkFileFilter* icvMakeGtkFilter(const char* name, const char* patterns, GtkFileFilter* images)
1589 GtkFileFilter* filter = gtk_file_filter_new();
1590 gtk_file_filter_set_name(filter, name);
1594 gtk_file_filter_add_pattern(filter, patterns);
1595 gtk_file_filter_add_pattern(images, patterns);
1596 patterns += strlen(patterns) + 1;
1602 static void icvShowSaveAsDialog(GtkWidget* widget, CvWindow* window)
1604 if (!window || !widget)
1607 CvImageWidget* image_widget = CV_IMAGE_WIDGET(window->widget);
1608 if (!image_widget || !image_widget->original_image)
1611 GtkWidget* dialog = gtk_file_chooser_dialog_new("Save As...",
1613 GTK_FILE_CHOOSER_ACTION_SAVE,
1614 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1615 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1617 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1619 cv::String sname = gtk_window_get_title(GTK_WINDOW(window->frame));
1620 sname = sname.substr(sname.find_last_of("\\/") + 1) + ".png";
1621 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), sname.c_str());
1623 GtkFileFilter* filter_all = gtk_file_filter_new();
1624 gtk_file_filter_set_name(filter_all, "All Files");
1625 gtk_file_filter_add_pattern(filter_all, "*");
1627 GtkFileFilter* filter_images = gtk_file_filter_new();
1628 gtk_file_filter_set_name(filter_images, "All Images");
1630 GtkFileFilter* file_filters[] = {
1631 icvMakeGtkFilter("Portable Network Graphics files (*.png)", "*.png\0", filter_images),
1632 icvMakeGtkFilter("JPEG files (*.jpeg;*.jpg;*.jpe)", "*.jpeg\0*.jpg\0*.jpe\0", filter_images),
1633 icvMakeGtkFilter("Windows bitmap (*.bmp;*.dib)", "*.bmp\0*.dib\0", filter_images),
1634 icvMakeGtkFilter("TIFF Files (*.tiff;*.tif)", "*.tiff\0*.tif\0", filter_images),
1635 icvMakeGtkFilter("JPEG-2000 files (*.jp2)", "*.jp2\0", filter_images),
1636 icvMakeGtkFilter("WebP files (*.webp)", "*.webp\0", filter_images),
1637 icvMakeGtkFilter("Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)", "*.pbm\0*.pgm\0*.ppm\0*.pxm\0*.pnm\0", filter_images),
1638 icvMakeGtkFilter("OpenEXR Image files (*.exr)", "*.exr\0", filter_images),
1639 icvMakeGtkFilter("Radiance HDR (*.hdr;*.pic)", "*.hdr\0*.pic\0", filter_images),
1640 icvMakeGtkFilter("Sun raster files (*.sr;*.ras)", "*.sr\0*.ras\0", filter_images),
1645 for (size_t idx = 0; idx < sizeof(file_filters)/sizeof(file_filters[0]); ++idx)
1646 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), file_filters[idx]); // filter ownership is transferred to dialog
1647 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter_images);
1649 cv::String filename;
1650 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1652 char* fname = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1656 gtk_widget_destroy(dialog);
1658 if (!filename.empty())
1661 cv::cvtColor(cv::cvarrToMat(image_widget->original_image), bgr, cv::COLOR_RGB2BGR);
1662 cv::imwrite(filename, bgr);
1666 #if defined (GTK_VERSION3)
1667 #define GDK_Escape GDK_KEY_Escape
1668 #define GDK_Return GDK_KEY_Return
1669 #define GDK_Linefeed GDK_KEY_Linefeed
1670 #define GDK_Tab GDK_KEY_Tab
1671 #define GDK_s GDK_KEY_s
1672 #define GDK_S GDK_KEY_S
1673 #endif //GTK_VERSION3
1675 static gboolean icvOnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
1679 if ( BIT_ALLIN(event->state, GDK_CONTROL_MASK) && (event->keyval == GDK_s || event->keyval == GDK_S))
1683 icvShowSaveAsDialog(widget, (CvWindow*)user_data);
1687 // suppress all exceptions here
1691 switch( event->keyval )
1704 code = event->keyval;
1707 code |= event->state << 16;
1712 g_mutex_lock(last_key_mutex);
1714 // signal any waiting threads
1715 g_cond_broadcast(cond_have_key);
1716 g_mutex_unlock(last_key_mutex);
1728 static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
1730 int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
1731 CvTrackbar* trackbar = (CvTrackbar*)user_data;
1733 if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
1734 trackbar->widget == widget )
1736 trackbar->pos = pos;
1737 if( trackbar->data )
1738 *trackbar->data = pos;
1739 if( trackbar->notify2 )
1740 trackbar->notify2(pos, trackbar->userdata);
1741 else if( trackbar->notify )
1742 trackbar->notify(pos);
1746 static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
1748 CvWindow* window = (CvWindow*)user_data;
1749 if( window->signature == CV_WINDOW_MAGIC_VAL &&
1750 window->frame == widget )
1752 icvDeleteWindow(window);
1758 static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
1760 // TODO move this logic to CvImageWidget
1761 CvWindow* window = (CvWindow*)user_data;
1762 CvPoint2D32f pt32f(-1., -1.);
1764 int cv_event = -1, state = 0, flags = 0;
1765 CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
1767 if( window->signature != CV_WINDOW_MAGIC_VAL ||
1768 window->widget != widget || !window->widget ||
1769 !window->on_mouse /*|| !image_widget->original_image*/)
1772 if( event->type == GDK_MOTION_NOTIFY )
1774 GdkEventMotion* event_motion = (GdkEventMotion*)event;
1776 cv_event = CV_EVENT_MOUSEMOVE;
1777 pt32f.x = cvRound(event_motion->x);
1778 pt32f.y = cvRound(event_motion->y);
1779 state = event_motion->state;
1781 else if( event->type == GDK_BUTTON_PRESS ||
1782 event->type == GDK_BUTTON_RELEASE ||
1783 event->type == GDK_2BUTTON_PRESS )
1785 GdkEventButton* event_button = (GdkEventButton*)event;
1786 pt32f.x = cvRound(event_button->x);
1787 pt32f.y = cvRound(event_button->y);
1790 if( event_button->type == GDK_BUTTON_PRESS )
1792 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
1793 event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
1794 event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
1796 else if( event_button->type == GDK_BUTTON_RELEASE )
1798 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
1799 event_button->button == 2 ? CV_EVENT_MBUTTONUP :
1800 event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
1802 else if( event_button->type == GDK_2BUTTON_PRESS )
1804 cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
1805 event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
1806 event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
1808 state = event_button->state;
1810 else if( event->type == GDK_SCROLL )
1812 #if defined(GTK_VERSION3_4)
1813 // NOTE: in current implementation doesn't possible to put into callback function delta_x and delta_y separetely
1814 double delta = (event->scroll.delta_x + event->scroll.delta_y);
1815 cv_event = (event->scroll.delta_y!=0) ? CV_EVENT_MOUSEHWHEEL : CV_EVENT_MOUSEWHEEL;
1817 cv_event = CV_EVENT_MOUSEWHEEL;
1818 #endif //GTK_VERSION3_4
1820 state = event->scroll.state;
1822 switch(event->scroll.direction) {
1823 #if defined(GTK_VERSION3_4)
1824 case GDK_SCROLL_SMOOTH: flags |= (((int)delta << 16));
1826 #endif //GTK_VERSION3_4
1827 case GDK_SCROLL_LEFT: cv_event = CV_EVENT_MOUSEHWHEEL;
1829 case GDK_SCROLL_UP: flags |= ~0xffff;
1831 case GDK_SCROLL_RIGHT: cv_event = CV_EVENT_MOUSEHWHEEL;
1833 case GDK_SCROLL_DOWN: flags |= (((int)1 << 16));
1841 // scale point if image is scaled
1842 if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
1843 image_widget->original_image &&
1844 image_widget->scaled_image )
1846 // image origin is not necessarily at (0,0)
1847 #if defined (GTK_VERSION3)
1848 int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2;
1849 int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2;
1851 int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
1852 int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
1853 #endif //GTK_VERSION3
1854 pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/
1855 image_widget->scaled_image->cols );
1856 pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/
1857 image_widget->scaled_image->rows );
1861 pt = cvPointFrom32f( pt32f );
1864 // if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
1865 // (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
1867 flags |= BIT_MAP(state, GDK_SHIFT_MASK, CV_EVENT_FLAG_SHIFTKEY) |
1868 BIT_MAP(state, GDK_CONTROL_MASK, CV_EVENT_FLAG_CTRLKEY) |
1869 BIT_MAP(state, GDK_MOD1_MASK, CV_EVENT_FLAG_ALTKEY) |
1870 BIT_MAP(state, GDK_MOD2_MASK, CV_EVENT_FLAG_ALTKEY) |
1871 BIT_MAP(state, GDK_BUTTON1_MASK, CV_EVENT_FLAG_LBUTTON) |
1872 BIT_MAP(state, GDK_BUTTON2_MASK, CV_EVENT_FLAG_MBUTTON) |
1873 BIT_MAP(state, GDK_BUTTON3_MASK, CV_EVENT_FLAG_RBUTTON);
1874 window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
1882 static gboolean icvAlarm( gpointer user_data )
1884 *(int*)user_data = 1;
1889 CV_IMPL int cvWaitKey( int delay )
1892 if (thread_started && g_thread_self() != window_thread)
1894 gboolean expired = true;
1897 g_mutex_lock(last_key_mutex);
1898 // wait for signal or timeout if delay > 0
1901 g_get_current_time(&timer);
1902 g_time_val_add(&timer, delay*1000);
1903 expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
1906 if (g_windows.empty())
1908 CV_LOG_WARNING(NULL, "cv::waitKey() is called without timeout and missing active windows. Ignoring");
1912 g_cond_wait(cond_have_key, last_key_mutex);
1916 my_last_key = last_key;
1917 g_mutex_unlock(last_key_mutex);
1918 if(expired || g_windows.empty()){
1929 timer = g_timeout_add( delay, icvAlarm, &expired );
1931 while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && (delay > 0 || !g_windows.empty()))
1934 if( delay > 0 && !expired )
1935 g_source_remove(timer);