Path: blob/master/modules/highgui/src/window_gtk.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "precomp.hpp"4243#ifndef _WIN324445#if defined (HAVE_GTK)4647#include <gtk/gtk.h>48#include <gdk/gdkkeysyms.h>49#include <gdk-pixbuf/gdk-pixbuf.h>50#include <stdio.h>5152#if (GTK_MAJOR_VERSION == 3)53#define GTK_VERSION3 154#endif //GTK_MAJOR_VERSION >= 355#if (GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4))56#define GTK_VERSION3_4 157#endif5859#ifdef HAVE_OPENGL60#include <gtk/gtkgl.h>61#include <GL/gl.h>62#include <GL/glu.h>63#endif6465#include <opencv2/core/utils/logger.hpp>66#include "opencv2/imgproc.hpp"6768using namespace cv;6970#ifndef BIT_ALLIN71#define BIT_ALLIN(x,y) ( ((x)&(y)) == (y) )72#endif73#ifndef BIT_MAP74#define BIT_MAP(x,y,z) ( ((x)&(y)) ? (z) : 0 )75#endif7677// TODO Fix the initial window size when flags=0. Right now the initial window is by default78// 320x240 size. A better default would be actual size of the image. Problem79// is determining desired window size with trackbars while still allowing resizing.80//81// Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio82// in totem/src/backend/bacon-video-widget-xine.c8384////////////////////////////////////////////////////////////85// CvImageWidget GTK Widget Public API86////////////////////////////////////////////////////////////87typedef struct _CvImageWidget CvImageWidget;88typedef struct _CvImageWidgetClass CvImageWidgetClass;8990struct _CvImageWidget {91GtkWidget widget;92CvMat * original_image;93CvMat * scaled_image;94int flags;95};9697struct _CvImageWidgetClass98{99GtkWidgetClass parent_class;100};101102103/** Allocate new image viewer widget */104GtkWidget* cvImageWidgetNew (int flags);105106/** Set the image to display in the widget */107void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr);108109// standard GTK object macros110#define CV_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, cvImageWidget_get_type (), CvImageWidget)111#define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass)112#define CV_IS_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, cvImageWidget_get_type ())113114/////////////////////////////////////////////////////////////////////////////115// Private API ////////////////////////////////////////////////////////116/////////////////////////////////////////////////////////////////////////////117GType cvImageWidget_get_type (void);118119static GtkWidgetClass * parent_class = NULL;120121// flag to help size initial window122#define CV_WINDOW_NO_IMAGE 2123124void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){125CvMat * mat, stub;126int origin=0;127128//printf("cvImageWidgetSetImage\n");129130if( CV_IS_IMAGE_HDR( arr ))131origin = ((IplImage*)arr)->origin;132133mat = cvGetMat(arr, &stub);134135if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){136cvReleaseMat( &widget->original_image );137}138if(!widget->original_image){139widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 );140gtk_widget_queue_resize( GTK_WIDGET( widget ) );141}142cvConvertImage( mat, widget->original_image,143(origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );144if(widget->scaled_image){145cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA );146}147148// window does not refresh without this149gtk_widget_queue_draw( GTK_WIDGET(widget) );150}151152GtkWidget*153cvImageWidgetNew (int flags)154{155CvImageWidget *image_widget;156157image_widget = CV_IMAGE_WIDGET( gtk_widget_new (cvImageWidget_get_type (), NULL) );158image_widget->original_image = 0;159image_widget->scaled_image = 0;160image_widget->flags = flags | CV_WINDOW_NO_IMAGE;161162return GTK_WIDGET (image_widget);163}164165static void166cvImageWidget_realize (GtkWidget *widget)167{168GdkWindowAttr attributes;169gint attributes_mask;170171#if defined(GTK_VERSION3)172GtkAllocation allocation;173gtk_widget_get_allocation(widget, &allocation);174#endif //GTK_VERSION3175176//printf("cvImageWidget_realize\n");177g_return_if_fail (widget != NULL);178g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));179180gtk_widget_set_realized(widget, TRUE);181182#if defined(GTK_VERSION3)183attributes.x = allocation.x;184attributes.y = allocation.y;185attributes.width = allocation.width;186attributes.height = allocation.height;187#else188attributes.x = widget->allocation.x;189attributes.y = widget->allocation.y;190attributes.width = widget->allocation.width;191attributes.height = widget->allocation.height;192#endif //GTK_VERSION3193194attributes.wclass = GDK_INPUT_OUTPUT;195attributes.window_type = GDK_WINDOW_CHILD;196attributes.event_mask = gtk_widget_get_events (widget) |197GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |198GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;199attributes.visual = gtk_widget_get_visual (widget);200201#if defined(GTK_VERSION3)202attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;203gtk_widget_set_window(204widget,205gdk_window_new(206gtk_widget_get_parent_window(widget),207&attributes,208attributes_mask209)210);211212gtk_widget_set_style(213widget,214gtk_style_attach(215gtk_widget_get_style(widget),216gtk_widget_get_window(widget)217)218);219220gdk_window_set_user_data (221gtk_widget_get_window(widget),222widget223);224225gtk_style_set_background (226gtk_widget_get_style(widget),227gtk_widget_get_window(widget),228GTK_STATE_ACTIVE229);230#else231// The following lines are included to prevent breaking232// compatibility with older Gtk2 (<gtk+-2.18) libraries.233attributes.colormap = gtk_widget_get_colormap (widget);234attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;235widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);236237widget->style = gtk_style_attach (widget->style, widget->window);238gdk_window_set_user_data (widget->window, widget);239240gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);241#endif // GTK_VERSION3242}243244static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){245float aspect = (float)im_width/(float)im_height;246float max_aspect = (float)max_width/(float)max_height;247if(aspect > max_aspect){248return cvSize( max_width, cvRound(max_width/aspect) );249}250return cvSize( cvRound(max_height*aspect), max_height );251}252253#if defined (GTK_VERSION3)254static void255cvImageWidget_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)256{257g_return_if_fail (widget != NULL);258g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));259CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );260261if(image_widget->original_image != NULL) {262*minimal_width = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ?263gdk_window_get_width(gtk_widget_get_window(widget)) : image_widget->original_image->cols;264}265else {266*minimal_width = 320;267}268269if(image_widget->scaled_image != NULL) {270*natural_width = *minimal_width < image_widget->scaled_image->cols ?271image_widget->scaled_image->cols : *minimal_width;272}273else {274*natural_width = *minimal_width;275}276}277278static void279cvImageWidget_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)280{281g_return_if_fail (widget != NULL);282g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));283CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );284285if(image_widget->original_image != NULL) {286*minimal_height = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ?287gdk_window_get_height(gtk_widget_get_window(widget)) : image_widget->original_image->rows;288}289else {290*minimal_height = 240;291}292293if(image_widget->scaled_image != NULL) {294*natural_height = *minimal_height < image_widget->scaled_image->rows ?295image_widget->scaled_image->rows : *minimal_height;296}297else {298*natural_height = *minimal_height;299}300}301302#else303static void304cvImageWidget_size_request (GtkWidget *widget,305GtkRequisition *requisition)306{307CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );308309//printf("cvImageWidget_size_request ");310// the case the first time cvShowImage called or when AUTOSIZE311if( image_widget->original_image &&312((image_widget->flags & CV_WINDOW_AUTOSIZE) ||313(image_widget->flags & CV_WINDOW_NO_IMAGE)))314{315//printf("original ");316requisition->width = image_widget->original_image->cols;317requisition->height = image_widget->original_image->rows;318}319// default case320else if(image_widget->scaled_image){321//printf("scaled ");322requisition->width = image_widget->scaled_image->cols;323requisition->height = image_widget->scaled_image->rows;324}325// the case before cvShowImage called326else{327//printf("default ");328requisition->width = 320;329requisition->height = 240;330}331//printf("%d %d\n",requisition->width, requisition->height);332}333#endif //GTK_VERSION3334335static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){336CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );337338//printf("cvImageWidget_set_size %d %d\n", max_width, max_height);339340// don't allow to set the size341if(image_widget->flags & CV_WINDOW_AUTOSIZE) return;342if(!image_widget->original_image) return;343344CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols,345image_widget->original_image->rows, max_width, max_height );346347if( image_widget->scaled_image &&348( image_widget->scaled_image->cols != scaled_image_size.width ||349image_widget->scaled_image->rows != scaled_image_size.height ))350{351cvReleaseMat( &image_widget->scaled_image );352}353if( !image_widget->scaled_image ){354image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 );355356357}358assert( image_widget->scaled_image );359}360361static void362cvImageWidget_size_allocate (GtkWidget *widget,363GtkAllocation *allocation)364{365CvImageWidget *image_widget;366367//printf("cvImageWidget_size_allocate\n");368g_return_if_fail (widget != NULL);369g_return_if_fail (CV_IS_IMAGE_WIDGET (widget));370g_return_if_fail (allocation != NULL);371372#if defined (GTK_VERSION3)373gtk_widget_set_allocation(widget, allocation);374#else375widget->allocation = *allocation;376#endif //GTK_VERSION3377image_widget = CV_IMAGE_WIDGET (widget);378379380if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){381// (re) allocated scaled image382if( image_widget->flags & CV_WINDOW_NO_IMAGE ){383cvImageWidget_set_size( widget, image_widget->original_image->cols,384image_widget->original_image->rows);385}386else{387cvImageWidget_set_size( widget, allocation->width, allocation->height );388}389cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA );390}391392if (gtk_widget_get_realized (widget))393{394image_widget = CV_IMAGE_WIDGET (widget);395396if( image_widget->original_image &&397((image_widget->flags & CV_WINDOW_AUTOSIZE) ||398(image_widget->flags & CV_WINDOW_NO_IMAGE)) )399{400#if defined (GTK_VERSION3)401allocation->width = image_widget->original_image->cols;402allocation->height = image_widget->original_image->rows;403gtk_widget_set_allocation(widget, allocation);404#else405widget->allocation.width = image_widget->original_image->cols;406widget->allocation.height = image_widget->original_image->rows;407#endif //GTK_VERSION3408gdk_window_move_resize( gtk_widget_get_window(widget),409allocation->x, allocation->y,410image_widget->original_image->cols, image_widget->original_image->rows );411if(image_widget->flags & CV_WINDOW_NO_IMAGE){412image_widget->flags &= ~CV_WINDOW_NO_IMAGE;413gtk_widget_queue_resize( GTK_WIDGET(widget) );414}415}416else{417gdk_window_move_resize (gtk_widget_get_window(widget),418allocation->x, allocation->y,419allocation->width, allocation->height );420}421}422}423424#if defined (GTK_VERSION3)425static void426cvImageWidget_destroy (GtkWidget *object)427#else428static void429cvImageWidget_destroy (GtkObject *object)430#endif //GTK_VERSION3431{432CvImageWidget *image_widget;433434g_return_if_fail (object != NULL);435g_return_if_fail (CV_IS_IMAGE_WIDGET (object));436437image_widget = CV_IMAGE_WIDGET (object);438439cvReleaseMat( &image_widget->scaled_image );440cvReleaseMat( &image_widget->original_image );441442#if defined (GTK_VERSION3)443if (GTK_WIDGET_CLASS (parent_class)->destroy)444(* GTK_WIDGET_CLASS (parent_class)->destroy) (object);445#else446if (GTK_OBJECT_CLASS (parent_class)->destroy)447(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);448#endif //GTK_VERSION3449}450451static void cvImageWidget_class_init (gpointer g_class, gpointer /*class_data*/)452{453CvImageWidgetClass* klass = (CvImageWidgetClass*)g_class;454#if defined (GTK_VERSION3)455GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);456#else457GtkObjectClass *object_class;458GtkWidgetClass *widget_class;459460object_class = (GtkObjectClass*) klass;461widget_class = (GtkWidgetClass*) klass;462#endif //GTK_VERSION3463464parent_class = GTK_WIDGET_CLASS( g_type_class_peek (gtk_widget_get_type ()) );465466#if defined (GTK_VERSION3)467widget_class->destroy = cvImageWidget_destroy;468widget_class->get_preferred_width = cvImageWidget_get_preferred_width;469widget_class->get_preferred_height = cvImageWidget_get_preferred_height;470#else471object_class->destroy = cvImageWidget_destroy;472widget_class->size_request = cvImageWidget_size_request;473#endif //GTK_VERSION3474475widget_class->realize = cvImageWidget_realize;476widget_class->size_allocate = cvImageWidget_size_allocate;477widget_class->button_press_event = NULL;478widget_class->button_release_event = NULL;479widget_class->motion_notify_event = NULL;480}481482static void483cvImageWidget_init(GTypeInstance* instance, gpointer /*g_class*/)484{485CvImageWidget* image_widget = (CvImageWidget*)instance;486image_widget->original_image=0;487image_widget->scaled_image=0;488image_widget->flags=0;489}490491GType cvImageWidget_get_type (void){492static GType image_type = 0;493494if (!image_type)495{496image_type = g_type_register_static_simple(497GTK_TYPE_WIDGET,498(gchar*) "CvImageWidget",499sizeof(CvImageWidgetClass),500cvImageWidget_class_init,501sizeof(CvImageWidget),502cvImageWidget_init,503(GTypeFlags)0504);505}506507return image_type;508}509/////////////////////////////////////////////////////////////////////////////510// End CvImageWidget511/////////////////////////////////////////////////////////////////////////////512513514struct CvWindow;515516struct CvUIBase {517CvUIBase(int signature_) : signature(signature_) { }518519int signature;520};521522struct CvTrackbar : CvUIBase523{524CvTrackbar(const char* trackbar_name) :525CvUIBase(CV_TRACKBAR_MAGIC_VAL),526widget(NULL), name(trackbar_name),527parent(NULL), data(NULL),528pos(0), maxval(0), minval(0),529notify(NULL), notify2(NULL), userdata(NULL)530{531// nothing532}533~CvTrackbar()534{535// destroyed by parent window536}537538GtkWidget* widget;539std::string name;540CvWindow* parent;541int* data;542int pos;543int maxval;544int minval;545CvTrackbarCallback notify;546CvTrackbarCallback2 notify2;547void* userdata;548};549550551struct CvWindow : CvUIBase552{553CvWindow(const char* window_name) :554CvUIBase(CV_WINDOW_MAGIC_VAL),555widget(NULL), frame(NULL), paned(NULL), name(window_name),556last_key(0), flags(0), status(0),557on_mouse(NULL), on_mouse_param(NULL)558#ifdef HAVE_OPENGL559,useGl(false), glDrawCallback(NULL), glDrawData(NULL)560#endif561{562// nothing563}564~CvWindow();565566GtkWidget* widget;567GtkWidget* frame;568GtkWidget* paned;569std::string name;570571int last_key;572int flags;573int status;//0 normal, 1 fullscreen (YV)574575CvMouseCallback on_mouse;576void* on_mouse_param;577578std::vector< Ptr<CvTrackbar> > trackbars;579580#ifdef HAVE_OPENGL581bool useGl;582583CvOpenGlDrawCallback glDrawCallback;584void* glDrawData;585#endif586};587588589static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );590static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );591static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );592static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );593594#ifdef HAVE_GTHREAD595int thread_started=0;596static gpointer icvWindowThreadLoop(gpointer data);597GMutex* last_key_mutex = NULL;598GCond* cond_have_key = NULL;599GThread* window_thread = NULL;600#endif601602static cv::Mutex& getWindowMutex()603{604static cv::Mutex* g_window_mutex = new cv::Mutex();605return *g_window_mutex;606}607608static int last_key = -1;609static std::vector< Ptr<CvWindow> > g_windows;610611CV_IMPL int cvInitSystem( int argc, char** argv )612{613static int wasInitialized = 0;614615// check initialization status616if( !wasInitialized )617{618gtk_init( &argc, &argv );619setlocale(LC_NUMERIC,"C");620621#ifdef HAVE_OPENGL622gtk_gl_init(&argc, &argv);623#endif624625wasInitialized = 1;626}627628return 0;629}630631CV_IMPL int cvStartWindowThread(){632#ifdef HAVE_GTHREAD633cvInitSystem(0,NULL);634if (!thread_started)635{636if (!g_thread_supported ()) {637/* the GThread system wasn't inited, so init it */638g_thread_init(NULL);639}640641(void)getWindowMutex(); // force mutex initialization642643// protects the 'last key pressed' variable644last_key_mutex = g_mutex_new();645646// conditional that indicates a key has been pressed647cond_have_key = g_cond_new();648649#if !GLIB_CHECK_VERSION(2, 32, 0)650// this is the window update thread651window_thread = g_thread_create(icvWindowThreadLoop,652NULL, TRUE, NULL);653#else654window_thread = g_thread_new("OpenCV window update", icvWindowThreadLoop, NULL);655#endif656}657thread_started = window_thread!=NULL;658return thread_started;659#else660return 0;661#endif662}663664#ifdef HAVE_GTHREAD665gpointer icvWindowThreadLoop(gpointer /*data*/)666{667while(1){668{669cv::AutoLock lock(getWindowMutex());670gtk_main_iteration_do(FALSE);671}672673// little sleep674g_usleep(500);675676g_thread_yield();677}678return NULL;679}680681#endif682683#define CV_LOCK_MUTEX() cv::AutoLock lock(getWindowMutex())684685static CvWindow* icvFindWindowByName( const char* name )686{687for(size_t i = 0; i < g_windows.size(); ++i)688{689CvWindow* window = g_windows[i].get();690if (window->name == name)691return window;692}693return NULL;694}695696static CvWindow* icvWindowByWidget( GtkWidget* widget )697{698for (size_t i = 0; i < g_windows.size(); ++i)699{700CvWindow* window = g_windows[i].get();701if (window->widget == widget || window->frame == widget || window->paned == widget)702return window;703}704return NULL;705}706707CvRect cvGetWindowRect_GTK(const char* name)708{709CV_Assert(name && "NULL name string");710711CV_LOCK_MUTEX();712CvWindow* window = icvFindWindowByName(name);713if (!window)714CV_Error( CV_StsNullPtr, "NULL window" );715716gint wx, wy;717#ifdef HAVE_OPENGL718if (window->useGl) {719gtk_widget_translate_coordinates(window->widget, gtk_widget_get_toplevel(window->widget), 0, 0, &wx, &wy);720return cvRect(wx, wy, window->widget->allocation.width, window->widget->allocation.height);721}722#endif723724CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );725gtk_widget_translate_coordinates(&image_widget->widget, gtk_widget_get_toplevel(&image_widget->widget), 0, 0, &wx, &wy);726if (image_widget->scaled_image) {727#if defined (GTK_VERSION3)728return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(window->widget)),729MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(window->widget)));730#else731return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, window->widget->allocation.width),732MIN(image_widget->scaled_image->rows, window->widget->allocation.height));733#endif //GTK_VERSION3734} else if (image_widget->original_image) {735#if defined (GTK_VERSION3)736return cvRect(wx, wy, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(window->widget)),737MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(window->widget)));738#else739return cvRect(wx, wy, MIN(image_widget->original_image->cols, window->widget->allocation.width),740MIN(image_widget->original_image->rows, window->widget->allocation.height));741#endif //GTK_VERSION3742}743744return cvRect(-1, -1, -1, -1);745}746747double cvGetModeWindow_GTK(const char* name)//YV748{749CV_Assert(name && "NULL name string");750751CV_LOCK_MUTEX();752CvWindow* window = icvFindWindowByName(name);753if (!window)754CV_Error( CV_StsNullPtr, "NULL window" );755756double result = window->status;757return result;758}759760761void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie762{763CV_Assert(name && "NULL name string");764765CV_LOCK_MUTEX();766767CvWindow* window = icvFindWindowByName(name);768if( !window )769CV_Error( CV_StsNullPtr, "NULL window" );770771if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set772return;773774//so easy to do fullscreen here, Linux rocks !775776if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)777{778gtk_window_unfullscreen(GTK_WINDOW(window->frame));779window->status=CV_WINDOW_NORMAL;780return;781}782783if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)784{785gtk_window_fullscreen(GTK_WINDOW(window->frame));786window->status=CV_WINDOW_FULLSCREEN;787return;788}789}790791void cv::setWindowTitle(const String& winname, const String& title)792{793CV_LOCK_MUTEX();794795CvWindow* window = icvFindWindowByName(winname.c_str());796797if (!window)798{799namedWindow(winname);800window = icvFindWindowByName(winname.c_str());801CV_Assert(window);802}803804gtk_window_set_title(GTK_WINDOW(window->frame), title.c_str());805}806807double cvGetPropWindowAutoSize_GTK(const char* name)808{809CV_Assert(name && "NULL name string");810811CV_LOCK_MUTEX();812813CvWindow* window = icvFindWindowByName(name);814if (!window)815return -1; // keep silence here816817double result = window->flags & CV_WINDOW_AUTOSIZE;818return result;819}820821double cvGetRatioWindow_GTK(const char* name)822{823CV_Assert(name && "NULL name string");824825CV_LOCK_MUTEX();826827CvWindow* window = icvFindWindowByName(name);828if (!window)829return -1; // keep silence here830831#if defined (GTK_VERSION3)832double result = static_cast<double>(833gtk_widget_get_allocated_width(window->widget)) / gtk_widget_get_allocated_height(window->widget);834#else835double result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;836#endif // GTK_VERSION3837return result;838}839840double cvGetOpenGlProp_GTK(const char* name)841{842#ifdef HAVE_OPENGL843CV_Assert(name && "NULL name string");844845CV_LOCK_MUTEX();846847CvWindow* window = icvFindWindowByName(name);848if (!window)849return -1; // keep silence here850851double result = window->useGl;852return result;853#else854(void)name;855return -1;856#endif857}858859860// OpenGL support861862#ifdef HAVE_OPENGL863864namespace865{866void createGlContext(CvWindow* window)867{868GdkGLConfig* glconfig;869870// Try double-buffered visual871glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));872if (!glconfig)873CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );874875// Set OpenGL-capability to the widget876if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))877CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );878879window->useGl = true;880}881882void drawGl(CvWindow* window)883{884GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);885GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);886887if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))888CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );889890glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);891892glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);893894if (window->glDrawCallback)895window->glDrawCallback(window->glDrawData);896897if (gdk_gl_drawable_is_double_buffered (gldrawable))898gdk_gl_drawable_swap_buffers(gldrawable);899else900glFlush();901902gdk_gl_drawable_gl_end(gldrawable);903}904}905906#endif // HAVE_OPENGL907908#if defined (GTK_VERSION3)909static gboolean cvImageWidget_draw(GtkWidget* widget, cairo_t *cr, gpointer data)910{911#ifdef HAVE_OPENGL912CvWindow* window = (CvWindow*)data;913914if (window->useGl)915{916drawGl(window);917return TRUE;918}919#else920(void)data;921#endif922923CvImageWidget *image_widget = NULL;924GdkPixbuf *pixbuf = NULL;925926g_return_val_if_fail (widget != NULL, FALSE);927g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);928929image_widget = CV_IMAGE_WIDGET (widget);930931if( image_widget->scaled_image ){932// center image in available region933#if defined (GTK_VERSION3)934int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2;935int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2;936#else937int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;938int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;939#endif //GTK_VERSION3940941#if defined (GTK_VERSION3)942pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,9438, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(widget)),944MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(widget)),945image_widget->scaled_image->step, NULL, NULL);946#else947pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,9488, MIN(image_widget->scaled_image->cols, widget->allocation.width),949MIN(image_widget->scaled_image->rows, widget->allocation.height),950image_widget->scaled_image->step, NULL, NULL);951#endif //GTK_VERSION3952953gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0);954}955else if( image_widget->original_image ){956#if defined (GTK_VERSION3)957pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,9588, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(widget)),959MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(widget)),960image_widget->original_image->step, NULL, NULL);961#else962pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,9638, MIN(image_widget->original_image->cols, widget->allocation.width),964MIN(image_widget->original_image->rows, widget->allocation.height),965image_widget->original_image->step, NULL, NULL);966#endif //GTK_VERSION3967gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);968}969970cairo_paint(cr);971if(pixbuf)972g_object_unref(pixbuf);973return TRUE;974}975976#else977static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)978{979#ifdef HAVE_OPENGL980CvWindow* window = (CvWindow*)data;981982if (window->useGl)983{984drawGl(window);985return TRUE;986}987#else988(void)data;989#endif990991CvImageWidget *image_widget = NULL;992cairo_t *cr = NULL;993GdkPixbuf *pixbuf = NULL;994995g_return_val_if_fail (widget != NULL, FALSE);996g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);997g_return_val_if_fail (event != NULL, FALSE);998999if (event->count > 0)1000return FALSE;10011002cr = gdk_cairo_create(widget->window);1003image_widget = CV_IMAGE_WIDGET (widget);10041005if( image_widget->scaled_image ){1006// center image in available region1007int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;1008int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;10091010pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false,10118, MIN(image_widget->scaled_image->cols, widget->allocation.width),1012MIN(image_widget->scaled_image->rows, widget->allocation.height),1013image_widget->scaled_image->step, NULL, NULL);10141015gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0);1016}1017else if( image_widget->original_image ){1018pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false,10198, MIN(image_widget->original_image->cols, widget->allocation.width),1020MIN(image_widget->original_image->rows, widget->allocation.height),1021image_widget->original_image->step, NULL, NULL);1022gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);1023}10241025cairo_paint(cr);1026if(pixbuf)1027g_object_unref(pixbuf);1028cairo_destroy(cr);1029return TRUE;1030}1031#endif //GTK_VERSION310321033CV_IMPL int cvNamedWindow( const char* name, int flags )1034{1035cvInitSystem(name ? 1 : 0,(char**)&name);1036CV_Assert(name && "NULL name string");10371038CV_LOCK_MUTEX();10391040// Check the name in the storage1041if (icvFindWindowByName(name))1042{1043return 1;1044}10451046Ptr<CvWindow> window = makePtr<CvWindow>(name);1047window->flags = flags;1048window->status = CV_WINDOW_NORMAL;//YV10491050window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );10511052window->paned = gtk_vbox_new( FALSE, 0 );1053window->widget = cvImageWidgetNew( flags );1054gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );1055gtk_widget_show( window->widget );1056gtk_container_add( GTK_CONTAINER(window->frame), window->paned );1057gtk_widget_show( window->paned );10581059#ifndef HAVE_OPENGL1060if (flags & CV_WINDOW_OPENGL)1061CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" );1062#else1063if (flags & CV_WINDOW_OPENGL)1064createGlContext(window);10651066window->glDrawCallback = 0;1067window->glDrawData = 0;1068#endif10691070//1071// configure event handlers1072// TODO -- move this to CvImageWidget ?1073g_signal_connect( window->frame, "key-press-event",1074G_CALLBACK(icvOnKeyPress), window );1075g_signal_connect( window->widget, "button-press-event",1076G_CALLBACK(icvOnMouse), window );1077g_signal_connect( window->widget, "button-release-event",1078G_CALLBACK(icvOnMouse), window );1079g_signal_connect( window->widget, "motion-notify-event",1080G_CALLBACK(icvOnMouse), window );1081g_signal_connect( window->widget, "scroll-event",1082G_CALLBACK(icvOnMouse), window );1083g_signal_connect( window->frame, "delete-event",1084G_CALLBACK(icvOnClose), window );1085#if defined(GTK_VERSION3)1086g_signal_connect( window->widget, "draw",1087G_CALLBACK(cvImageWidget_draw), window );1088#else1089g_signal_connect( window->widget, "expose-event",1090G_CALLBACK(cvImageWidget_expose), window );1091#endif //GTK_VERSION3109210931094#if defined(GTK_VERSION3_4)1095gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK) ;1096#else1097gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK) ;1098#endif //GTK_VERSION3_410991100gtk_widget_show( window->frame );1101gtk_window_set_title( GTK_WINDOW(window->frame), name );11021103g_windows.push_back(window);11041105bool b_nautosize = ((flags & CV_WINDOW_AUTOSIZE) == 0);1106gtk_window_set_resizable( GTK_WINDOW(window->frame), b_nautosize );11071108// allow window to be resized1109if( b_nautosize ){1110GdkGeometry geometry;1111geometry.min_width = 50;1112geometry.min_height = 50;1113gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),1114&geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));1115}11161117#ifdef HAVE_OPENGL1118if (window->useGl)1119cvSetOpenGlContext(name);1120#endif11211122return 1;1123}112411251126#ifdef HAVE_OPENGL11271128CV_IMPL void cvSetOpenGlContext(const char* name)1129{1130GdkGLContext* glcontext;1131GdkGLDrawable* gldrawable;11321133CV_Assert(name && "NULL name string");11341135CV_LOCK_MUTEX();11361137CvWindow* window = icvFindWindowByName(name);1138if (!window)1139CV_Error( CV_StsNullPtr, "NULL window" );11401141if (!window->useGl)1142CV_Error( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );11431144glcontext = gtk_widget_get_gl_context(window->widget);1145gldrawable = gtk_widget_get_gl_drawable(window->widget);11461147if (!gdk_gl_drawable_make_current(gldrawable, glcontext))1148CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );1149}11501151CV_IMPL void cvUpdateWindow(const char* name)1152{1153CV_Assert(name && "NULL name string");11541155CV_LOCK_MUTEX();11561157CvWindow* window = icvFindWindowByName(name);1158if (!window)1159return;11601161// window does not refresh without this1162gtk_widget_queue_draw( GTK_WIDGET(window->widget) );1163}11641165CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)1166{1167CV_Assert(name && "NULL name string");11681169CV_LOCK_MUTEX();11701171CvWindow* window = icvFindWindowByName(name);1172if( !window )1173return;11741175if (!window->useGl)1176CV_Error( CV_OpenGlNotSupported, "Window was created without OpenGL context" );11771178window->glDrawCallback = callback;1179window->glDrawData = userdata;1180}11811182#endif // HAVE_OPENGL1183118411851186CvWindow::~CvWindow()1187{1188gtk_widget_destroy(frame);1189}11901191static void checkLastWindow()1192{1193// if last window...1194if (g_windows.empty())1195{1196#ifdef HAVE_GTHREAD1197if( thread_started )1198{1199// send key press signal to jump out of any waiting cvWaitKey's1200g_cond_broadcast( cond_have_key );1201}1202else1203{1204#endif1205// Some GTK+ modules (like the Unity module) use GDBusConnection,1206// which has a habit of postponing cleanup by performing it via1207// idle sources added to the main loop. Since this was the last window,1208// we can assume that no event processing is going to happen in the1209// nearest future, so we should force that cleanup (by handling all pending1210// events) while we still have the chance.1211// This is not needed if thread_started is true, because the background1212// thread will process events continuously.1213while( gtk_events_pending() )1214gtk_main_iteration();1215#ifdef HAVE_GTHREAD1216}1217#endif1218}1219}12201221static void icvDeleteWindow( CvWindow* window )1222{1223bool found = false;1224for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin();1225i != g_windows.end(); ++i)1226{1227if (i->get() == window)1228{1229g_windows.erase(i);1230found = true;1231break;1232}1233}1234CV_Assert(found && "Can't destroy non-registered window");12351236checkLastWindow();1237}12381239CV_IMPL void cvDestroyWindow( const char* name )1240{1241CV_Assert(name && "NULL name string");12421243CV_LOCK_MUTEX();12441245bool found = false;1246for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin();1247i != g_windows.end(); ++i)1248{1249if (i->get()->name == name)1250{1251g_windows.erase(i);1252found = true;1253break;1254}1255}1256CV_Assert(found && "Can't destroy non-registered window");12571258checkLastWindow();1259}126012611262CV_IMPL void1263cvDestroyAllWindows( void )1264{1265CV_LOCK_MUTEX();12661267g_windows.clear();1268checkLastWindow();1269}12701271// CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){1272// CvSize window_size;1273// GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );1274// gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),1275// &window_size.width, &window_size.height );12761277// window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;1278// window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;12791280// return window_size;1281// }12821283CV_IMPL void1284cvShowImage( const char* name, const CvArr* arr )1285{1286CV_Assert(name && "NULL name string");12871288CV_LOCK_MUTEX();12891290CvWindow* window = icvFindWindowByName(name);1291if(!window)1292{1293cvNamedWindow(name, 1);1294window = icvFindWindowByName(name);1295}1296CV_Assert(window);12971298if (arr)1299{1300#ifdef HAVE_OPENGL1301if (window->useGl)1302{1303cv::imshow(name, cv::cvarrToMat(arr));1304return;1305}1306#endif13071308CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );1309cvImageWidgetSetImage( image_widget, arr );1310}1311}13121313CV_IMPL void cvResizeWindow(const char* name, int width, int height )1314{1315CV_Assert(name && "NULL name string");13161317CV_LOCK_MUTEX();13181319CvWindow* window = icvFindWindowByName(name);1320if(!window)1321return;13221323CvImageWidget* image_widget = CV_IMAGE_WIDGET( window->widget );1324//if(image_widget->flags & CV_WINDOW_AUTOSIZE)1325//EXIT;13261327gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );1328gtk_window_resize( GTK_WINDOW(window->frame), width, height );13291330// disable initial resize since presumably user wants to keep1331// this window size1332image_widget->flags &= ~CV_WINDOW_NO_IMAGE;1333}133413351336CV_IMPL void cvMoveWindow( const char* name, int x, int y )1337{1338CV_Assert(name && "NULL name string");13391340CV_LOCK_MUTEX();13411342CvWindow* window = icvFindWindowByName(name);1343if(!window)1344return;13451346gtk_window_move( GTK_WINDOW(window->frame), x, y );1347}134813491350static CvTrackbar*1351icvFindTrackbarByName( const CvWindow* window, const char* name )1352{1353for (size_t i = 0; i < window->trackbars.size(); ++i)1354{1355CvTrackbar* trackbar = window->trackbars[i].get();1356if (trackbar->name == name)1357return trackbar;1358}1359return NULL;1360}13611362static int1363icvCreateTrackbar( const char* trackbar_name, const char* window_name,1364int* val, int count, CvTrackbarCallback on_notify,1365CvTrackbarCallback2 on_notify2, void* userdata )1366{1367CV_Assert(window_name && "NULL window name");1368CV_Assert(trackbar_name && "NULL trackbar name");13691370if( count <= 0 )1371CV_Error( CV_StsOutOfRange, "Bad trackbar maximal value" );13721373CV_LOCK_MUTEX();13741375CvWindow* window = icvFindWindowByName(window_name);1376if(!window)1377return 0;13781379CvTrackbar* trackbar = icvFindTrackbarByName(window, trackbar_name);1380if (!trackbar)1381{1382Ptr<CvTrackbar> trackbar_ = makePtr<CvTrackbar>(trackbar_name);1383trackbar = trackbar_.get();1384trackbar->parent = window;1385window->trackbars.push_back(trackbar_);13861387GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );1388GtkWidget* hscale_label = gtk_label_new( trackbar_name );1389GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );1390gtk_scale_set_digits( GTK_SCALE(hscale), 0 );1391//gtk_scale_set_value_pos( hscale, GTK_POS_TOP );1392gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE );13931394trackbar->widget = hscale;1395gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 );1396gtk_widget_show( hscale_label );1397gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 );1398gtk_widget_show( hscale );1399gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 );1400gtk_widget_show( hscale_box );1401}14021403if( val )1404{1405int value = *val;1406if( value < 0 )1407value = 0;1408if( value > count )1409value = count;1410gtk_range_set_value( GTK_RANGE(trackbar->widget), value );1411trackbar->pos = value;1412trackbar->data = val;1413}14141415trackbar->maxval = count;1416trackbar->notify = on_notify;1417trackbar->notify2 = on_notify2;1418trackbar->userdata = userdata;1419g_signal_connect( trackbar->widget, "value-changed",1420G_CALLBACK(icvOnTrackbar), trackbar );14211422// queue a widget resize to trigger a window resize to1423// compensate for the addition of trackbars1424gtk_widget_queue_resize( GTK_WIDGET(window->widget) );14251426return 1;1427}142814291430CV_IMPL int1431cvCreateTrackbar( const char* trackbar_name, const char* window_name,1432int* val, int count, CvTrackbarCallback on_notify )1433{1434return icvCreateTrackbar(trackbar_name, window_name, val, count,1435on_notify, 0, 0);1436}143714381439CV_IMPL int1440cvCreateTrackbar2( const char* trackbar_name, const char* window_name,1441int* val, int count, CvTrackbarCallback2 on_notify2,1442void* userdata )1443{1444return icvCreateTrackbar(trackbar_name, window_name, val, count,14450, on_notify2, userdata);1446}144714481449CV_IMPL void1450cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )1451{1452CV_Assert(window_name && "NULL window name");14531454CV_LOCK_MUTEX();14551456CvWindow* window = icvFindWindowByName(window_name);1457if (!window)1458return;14591460window->on_mouse = on_mouse;1461window->on_mouse_param = param;1462}146314641465CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )1466{1467CV_Assert(window_name && "NULL window name");1468CV_Assert(trackbar_name && "NULL trackbar name");14691470CV_LOCK_MUTEX();14711472CvWindow* window = icvFindWindowByName(window_name);1473if (!window)1474return -1;14751476CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);1477if (!trackbar)1478return -1;14791480return trackbar->pos;1481}148214831484CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )1485{1486CV_Assert(window_name && "NULL window name");1487CV_Assert(trackbar_name && "NULL trackbar name");14881489CV_LOCK_MUTEX();14901491CvWindow* window = icvFindWindowByName(window_name);1492if(!window)1493return;14941495CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);1496if( trackbar )1497{1498if( pos < trackbar->minval )1499pos = trackbar->minval;15001501if( pos > trackbar->maxval )1502pos = trackbar->maxval;1503}1504else1505{1506CV_Error( CV_StsNullPtr, "No trackbar found" );1507}15081509gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );1510}151115121513CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)1514{1515CV_Assert(window_name && "NULL window name");1516CV_Assert(trackbar_name && "NULL trackbar name");15171518CV_LOCK_MUTEX();15191520CvWindow* window = icvFindWindowByName(window_name);1521if(!window)1522return;15231524CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);1525if(!trackbar)1526return;15271528trackbar->maxval = maxval;1529if (trackbar->maxval >= trackbar->minval)1530gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval);1531}153215331534CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)1535{1536CV_Assert(window_name && "NULL window name");1537CV_Assert(trackbar_name && "NULL trackbar name");15381539CV_LOCK_MUTEX();15401541CvWindow* window = icvFindWindowByName(window_name);1542if(!window)1543return;15441545CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name);1546if(!trackbar)1547return;15481549trackbar->minval = minval;1550if (trackbar->maxval >= trackbar->minval)1551gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval);1552}155315541555CV_IMPL void* cvGetWindowHandle( const char* window_name )1556{1557CV_Assert(window_name && "NULL window name");15581559CV_LOCK_MUTEX();15601561CvWindow* window = icvFindWindowByName(window_name);1562if(!window)1563return NULL;15641565return (void*)window->widget;1566}156715681569CV_IMPL const char* cvGetWindowName( void* window_handle )1570{1571CV_Assert(window_handle && "NULL window handle");15721573CV_LOCK_MUTEX();15741575CvWindow* window = icvWindowByWidget( (GtkWidget*)window_handle );1576if (window)1577return window->name.c_str();15781579return ""; // FIXME: NULL?1580}15811582static GtkFileFilter* icvMakeGtkFilter(const char* name, const char* patterns, GtkFileFilter* images)1583{1584GtkFileFilter* filter = gtk_file_filter_new();1585gtk_file_filter_set_name(filter, name);15861587while(patterns[0])1588{1589gtk_file_filter_add_pattern(filter, patterns);1590gtk_file_filter_add_pattern(images, patterns);1591patterns += strlen(patterns) + 1;1592}15931594return filter;1595}15961597static void icvShowSaveAsDialog(GtkWidget* widget, CvWindow* window)1598{1599if (!window || !widget)1600return;16011602CvImageWidget* image_widget = CV_IMAGE_WIDGET(window->widget);1603if (!image_widget || !image_widget->original_image)1604return;16051606GtkWidget* dialog = gtk_file_chooser_dialog_new("Save As...",1607GTK_WINDOW(widget),1608GTK_FILE_CHOOSER_ACTION_SAVE,1609GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,1610GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,1611NULL);1612gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);16131614cv::String sname = gtk_window_get_title(GTK_WINDOW(window->frame));1615sname = sname.substr(sname.find_last_of("\\/") + 1) + ".png";1616gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), sname.c_str());16171618GtkFileFilter* filter_all = gtk_file_filter_new();1619gtk_file_filter_set_name(filter_all, "All Files");1620gtk_file_filter_add_pattern(filter_all, "*");16211622GtkFileFilter* filter_images = gtk_file_filter_new();1623gtk_file_filter_set_name(filter_images, "All Images");16241625GtkFileFilter* file_filters[] = {1626icvMakeGtkFilter("Portable Network Graphics files (*.png)", "*.png\0", filter_images),1627icvMakeGtkFilter("JPEG files (*.jpeg;*.jpg;*.jpe)", "*.jpeg\0*.jpg\0*.jpe\0", filter_images),1628icvMakeGtkFilter("Windows bitmap (*.bmp;*.dib)", "*.bmp\0*.dib\0", filter_images),1629icvMakeGtkFilter("TIFF Files (*.tiff;*.tif)", "*.tiff\0*.tif\0", filter_images),1630icvMakeGtkFilter("JPEG-2000 files (*.jp2)", "*.jp2\0", filter_images),1631icvMakeGtkFilter("WebP files (*.webp)", "*.webp\0", filter_images),1632icvMakeGtkFilter("Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)", "*.pbm\0*.pgm\0*.ppm\0*.pxm\0*.pnm\0", filter_images),1633icvMakeGtkFilter("OpenEXR Image files (*.exr)", "*.exr\0", filter_images),1634icvMakeGtkFilter("Radiance HDR (*.hdr;*.pic)", "*.hdr\0*.pic\0", filter_images),1635icvMakeGtkFilter("Sun raster files (*.sr;*.ras)", "*.sr\0*.ras\0", filter_images),1636filter_images,1637filter_all1638};16391640for (size_t idx = 0; idx < sizeof(file_filters)/sizeof(file_filters[0]); ++idx)1641gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), file_filters[idx]); // filter ownership is transferred to dialog1642gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter_images);16431644cv::String filename;1645if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)1646{1647char* fname = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));1648filename = fname;1649g_free(fname);1650}1651gtk_widget_destroy(dialog);16521653if (!filename.empty())1654{1655cv::Mat bgr;1656cv::cvtColor(cv::cvarrToMat(image_widget->original_image), bgr, cv::COLOR_RGB2BGR);1657cv::imwrite(filename, bgr);1658}1659}16601661#if defined (GTK_VERSION3)1662#define GDK_Escape GDK_KEY_Escape1663#define GDK_Return GDK_KEY_Return1664#define GDK_Linefeed GDK_KEY_Linefeed1665#define GDK_Tab GDK_KEY_Tab1666#define GDK_s GDK_KEY_s1667#define GDK_S GDK_KEY_S1668#endif //GTK_VERSION316691670static gboolean icvOnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer user_data)1671{1672int code = 0;16731674if ( BIT_ALLIN(event->state, GDK_CONTROL_MASK) && (event->keyval == GDK_s || event->keyval == GDK_S))1675{1676try1677{1678icvShowSaveAsDialog(widget, (CvWindow*)user_data);1679}1680catch(...)1681{1682// suppress all exceptions here1683}1684}16851686switch( event->keyval )1687{1688case GDK_Escape:1689code = 27;1690break;1691case GDK_Return:1692case GDK_Linefeed:1693code = 13;1694break;1695case GDK_Tab:1696code = '\t';1697break;1698default:1699code = event->keyval;1700}17011702code |= event->state << 16;17031704#ifdef HAVE_GTHREAD1705if(thread_started)1706{1707g_mutex_lock(last_key_mutex);1708last_key = code;1709// signal any waiting threads1710g_cond_broadcast(cond_have_key);1711g_mutex_unlock(last_key_mutex);1712}1713else1714#endif1715{1716last_key = code;1717}17181719return FALSE;1720}172117221723static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )1724{1725int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));1726CvTrackbar* trackbar = (CvTrackbar*)user_data;17271728if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&1729trackbar->widget == widget )1730{1731trackbar->pos = pos;1732if( trackbar->data )1733*trackbar->data = pos;1734if( trackbar->notify2 )1735trackbar->notify2(pos, trackbar->userdata);1736else if( trackbar->notify )1737trackbar->notify(pos);1738}1739}17401741static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )1742{1743CvWindow* window = (CvWindow*)user_data;1744if( window->signature == CV_WINDOW_MAGIC_VAL &&1745window->frame == widget )1746{1747icvDeleteWindow(window);1748}1749return TRUE;1750}175117521753static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )1754{1755// TODO move this logic to CvImageWidget1756CvWindow* window = (CvWindow*)user_data;1757CvPoint2D32f pt32f = {-1., -1.};1758CvPoint pt = {-1,-1};1759int cv_event = -1, state = 0, flags = 0;1760CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );17611762if( window->signature != CV_WINDOW_MAGIC_VAL ||1763window->widget != widget || !window->widget ||1764!window->on_mouse /*|| !image_widget->original_image*/)1765return FALSE;17661767if( event->type == GDK_MOTION_NOTIFY )1768{1769GdkEventMotion* event_motion = (GdkEventMotion*)event;17701771cv_event = CV_EVENT_MOUSEMOVE;1772pt32f.x = cvRound(event_motion->x);1773pt32f.y = cvRound(event_motion->y);1774state = event_motion->state;1775}1776else if( event->type == GDK_BUTTON_PRESS ||1777event->type == GDK_BUTTON_RELEASE ||1778event->type == GDK_2BUTTON_PRESS )1779{1780GdkEventButton* event_button = (GdkEventButton*)event;1781pt32f.x = cvRound(event_button->x);1782pt32f.y = cvRound(event_button->y);178317841785if( event_button->type == GDK_BUTTON_PRESS )1786{1787cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :1788event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :1789event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;1790}1791else if( event_button->type == GDK_BUTTON_RELEASE )1792{1793cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :1794event_button->button == 2 ? CV_EVENT_MBUTTONUP :1795event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;1796}1797else if( event_button->type == GDK_2BUTTON_PRESS )1798{1799cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :1800event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :1801event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;1802}1803state = event_button->state;1804}1805else if( event->type == GDK_SCROLL )1806{1807#if defined(GTK_VERSION3_4)1808// NOTE: in current implementation doesn't possible to put into callback function delta_x and delta_y separetely1809double delta = (event->scroll.delta_x + event->scroll.delta_y);1810cv_event = (event->scroll.delta_y!=0) ? CV_EVENT_MOUSEHWHEEL : CV_EVENT_MOUSEWHEEL;1811#else1812cv_event = CV_EVENT_MOUSEWHEEL;1813#endif //GTK_VERSION3_418141815state = event->scroll.state;18161817switch(event->scroll.direction) {1818#if defined(GTK_VERSION3_4)1819case GDK_SCROLL_SMOOTH: flags |= (((int)delta << 16));1820break;1821#endif //GTK_VERSION3_41822case GDK_SCROLL_LEFT: cv_event = CV_EVENT_MOUSEHWHEEL;1823/* FALLTHRU */1824case GDK_SCROLL_UP: flags |= ~0xffff;1825break;1826case GDK_SCROLL_RIGHT: cv_event = CV_EVENT_MOUSEHWHEEL;1827/* FALLTHRU */1828case GDK_SCROLL_DOWN: flags |= (((int)1 << 16));1829break;1830default: ;1831};1832}18331834if( cv_event >= 0 )1835{1836// scale point if image is scaled1837if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&1838image_widget->original_image &&1839image_widget->scaled_image )1840{1841// image origin is not necessarily at (0,0)1842#if defined (GTK_VERSION3)1843int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2;1844int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2;1845#else1846int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;1847int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;1848#endif //GTK_VERSION31849pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/1850image_widget->scaled_image->cols );1851pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/1852image_widget->scaled_image->rows );1853}1854else1855{1856pt = cvPointFrom32f( pt32f );1857}18581859// if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&1860// (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )1861{1862flags |= BIT_MAP(state, GDK_SHIFT_MASK, CV_EVENT_FLAG_SHIFTKEY) |1863BIT_MAP(state, GDK_CONTROL_MASK, CV_EVENT_FLAG_CTRLKEY) |1864BIT_MAP(state, GDK_MOD1_MASK, CV_EVENT_FLAG_ALTKEY) |1865BIT_MAP(state, GDK_MOD2_MASK, CV_EVENT_FLAG_ALTKEY) |1866BIT_MAP(state, GDK_BUTTON1_MASK, CV_EVENT_FLAG_LBUTTON) |1867BIT_MAP(state, GDK_BUTTON2_MASK, CV_EVENT_FLAG_MBUTTON) |1868BIT_MAP(state, GDK_BUTTON3_MASK, CV_EVENT_FLAG_RBUTTON);1869window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );1870}1871}18721873return FALSE;1874}187518761877static gboolean icvAlarm( gpointer user_data )1878{1879*(int*)user_data = 1;1880return FALSE;1881}188218831884CV_IMPL int cvWaitKey( int delay )1885{1886#ifdef HAVE_GTHREAD1887if (thread_started && g_thread_self() != window_thread)1888{1889gboolean expired = true;1890int my_last_key;18911892g_mutex_lock(last_key_mutex);1893// wait for signal or timeout if delay > 01894if(delay>0){1895GTimeVal timer;1896g_get_current_time(&timer);1897g_time_val_add(&timer, delay*1000);1898expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);1899}1900else{1901if (g_windows.empty())1902{1903CV_LOG_WARNING(NULL, "cv::waitKey() is called without timeout and missing active windows. Ignoring");1904}1905else1906{1907g_cond_wait(cond_have_key, last_key_mutex);1908expired=false;1909}1910}1911my_last_key = last_key;1912g_mutex_unlock(last_key_mutex);1913if(expired || g_windows.empty()){1914return -1;1915}1916return my_last_key;1917}1918else1919#endif1920{1921int expired = 0;1922guint timer = 0;1923if( delay > 0 )1924timer = g_timeout_add( delay, icvAlarm, &expired );1925last_key = -1;1926while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && (delay > 0 || !g_windows.empty()))1927;19281929if( delay > 0 && !expired )1930g_source_remove(timer);1931}1932return last_key;1933}193419351936#endif // HAVE_GTK1937#endif // _WIN3219381939/* End of file. */194019411942