mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1940 lines
58 KiB
1940 lines
58 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// Intel License Agreement |
|
// For Open Source Computer Vision Library |
|
// |
|
// Copyright (C) 2000, Intel Corporation, all rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of Intel Corporation may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
|
|
#include "precomp.hpp" |
|
|
|
#ifndef _WIN32 |
|
|
|
#if defined (HAVE_GTK) |
|
|
|
#include <gtk/gtk.h> |
|
#include <gdk/gdkkeysyms.h> |
|
#include <gdk-pixbuf/gdk-pixbuf.h> |
|
#include <stdio.h> |
|
|
|
#if (GTK_MAJOR_VERSION == 3) |
|
#define GTK_VERSION3 1 |
|
#endif //GTK_MAJOR_VERSION >= 3 |
|
#if (GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)) |
|
#define GTK_VERSION3_4 1 |
|
#endif |
|
|
|
#ifdef HAVE_OPENGL |
|
#include <gtk/gtkgl.h> |
|
#include <GL/gl.h> |
|
#include <GL/glu.h> |
|
#endif |
|
|
|
#include <opencv2/core/utils/logger.hpp> |
|
#include "opencv2/imgproc.hpp" |
|
|
|
using namespace cv; |
|
|
|
#ifndef BIT_ALLIN |
|
#define BIT_ALLIN(x,y) ( ((x)&(y)) == (y) ) |
|
#endif |
|
#ifndef BIT_MAP |
|
#define BIT_MAP(x,y,z) ( ((x)&(y)) ? (z) : 0 ) |
|
#endif |
|
|
|
// TODO Fix the initial window size when flags=0. Right now the initial window is by default |
|
// 320x240 size. A better default would be actual size of the image. Problem |
|
// is determining desired window size with trackbars while still allowing resizing. |
|
// |
|
// Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio |
|
// in totem/src/backend/bacon-video-widget-xine.c |
|
|
|
//////////////////////////////////////////////////////////// |
|
// CvImageWidget GTK Widget Public API |
|
//////////////////////////////////////////////////////////// |
|
typedef struct _CvImageWidget CvImageWidget; |
|
typedef struct _CvImageWidgetClass CvImageWidgetClass; |
|
|
|
struct _CvImageWidget { |
|
GtkWidget widget; |
|
CvMat * original_image; |
|
CvMat * scaled_image; |
|
int flags; |
|
}; |
|
|
|
struct _CvImageWidgetClass |
|
{ |
|
GtkWidgetClass parent_class; |
|
}; |
|
|
|
|
|
/** Allocate new image viewer widget */ |
|
GtkWidget* cvImageWidgetNew (int flags); |
|
|
|
/** Set the image to display in the widget */ |
|
void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr); |
|
|
|
// standard GTK object macros |
|
#define CV_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, cvImageWidget_get_type (), CvImageWidget) |
|
#define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass) |
|
#define CV_IS_IMAGE_WIDGET(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, cvImageWidget_get_type ()) |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// Private API //////////////////////////////////////////////////////// |
|
///////////////////////////////////////////////////////////////////////////// |
|
GType cvImageWidget_get_type (void); |
|
|
|
static GtkWidgetClass * parent_class = NULL; |
|
|
|
// flag to help size initial window |
|
#define CV_WINDOW_NO_IMAGE 2 |
|
|
|
void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){ |
|
CvMat * mat, stub; |
|
int origin=0; |
|
|
|
//printf("cvImageWidgetSetImage\n"); |
|
|
|
if( CV_IS_IMAGE_HDR( arr )) |
|
origin = ((IplImage*)arr)->origin; |
|
|
|
mat = cvGetMat(arr, &stub); |
|
|
|
if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){ |
|
cvReleaseMat( &widget->original_image ); |
|
} |
|
if(!widget->original_image){ |
|
widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 ); |
|
gtk_widget_queue_resize( GTK_WIDGET( widget ) ); |
|
} |
|
cvConvertImage( mat, widget->original_image, |
|
(origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB ); |
|
if(widget->scaled_image){ |
|
cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA ); |
|
} |
|
|
|
// window does not refresh without this |
|
gtk_widget_queue_draw( GTK_WIDGET(widget) ); |
|
} |
|
|
|
GtkWidget* |
|
cvImageWidgetNew (int flags) |
|
{ |
|
CvImageWidget *image_widget; |
|
|
|
image_widget = CV_IMAGE_WIDGET( gtk_widget_new (cvImageWidget_get_type (), NULL) ); |
|
image_widget->original_image = 0; |
|
image_widget->scaled_image = 0; |
|
image_widget->flags = flags | CV_WINDOW_NO_IMAGE; |
|
|
|
return GTK_WIDGET (image_widget); |
|
} |
|
|
|
static void |
|
cvImageWidget_realize (GtkWidget *widget) |
|
{ |
|
GdkWindowAttr attributes; |
|
gint attributes_mask; |
|
|
|
#if defined(GTK_VERSION3) |
|
GtkAllocation allocation; |
|
gtk_widget_get_allocation(widget, &allocation); |
|
#endif //GTK_VERSION3 |
|
|
|
//printf("cvImageWidget_realize\n"); |
|
g_return_if_fail (widget != NULL); |
|
g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); |
|
|
|
gtk_widget_set_realized(widget, TRUE); |
|
|
|
#if defined(GTK_VERSION3) |
|
attributes.x = allocation.x; |
|
attributes.y = allocation.y; |
|
attributes.width = allocation.width; |
|
attributes.height = allocation.height; |
|
#else |
|
attributes.x = widget->allocation.x; |
|
attributes.y = widget->allocation.y; |
|
attributes.width = widget->allocation.width; |
|
attributes.height = widget->allocation.height; |
|
#endif //GTK_VERSION3 |
|
|
|
attributes.wclass = GDK_INPUT_OUTPUT; |
|
attributes.window_type = GDK_WINDOW_CHILD; |
|
attributes.event_mask = gtk_widget_get_events (widget) | |
|
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | |
|
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; |
|
attributes.visual = gtk_widget_get_visual (widget); |
|
|
|
#if defined(GTK_VERSION3) |
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; |
|
gtk_widget_set_window( |
|
widget, |
|
gdk_window_new( |
|
gtk_widget_get_parent_window(widget), |
|
&attributes, |
|
attributes_mask |
|
) |
|
); |
|
|
|
gtk_widget_set_style( |
|
widget, |
|
gtk_style_attach( |
|
gtk_widget_get_style(widget), |
|
gtk_widget_get_window(widget) |
|
) |
|
); |
|
|
|
gdk_window_set_user_data ( |
|
gtk_widget_get_window(widget), |
|
widget |
|
); |
|
|
|
gtk_style_set_background ( |
|
gtk_widget_get_style(widget), |
|
gtk_widget_get_window(widget), |
|
GTK_STATE_ACTIVE |
|
); |
|
#else |
|
// The following lines are included to prevent breaking |
|
// compatibility with older Gtk2 (<gtk+-2.18) libraries. |
|
attributes.colormap = gtk_widget_get_colormap (widget); |
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; |
|
widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); |
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window); |
|
gdk_window_set_user_data (widget->window, widget); |
|
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); |
|
#endif // GTK_VERSION3 |
|
} |
|
|
|
static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){ |
|
float aspect = (float)im_width/(float)im_height; |
|
float max_aspect = (float)max_width/(float)max_height; |
|
if(aspect > max_aspect){ |
|
return cvSize( max_width, cvRound(max_width/aspect) ); |
|
} |
|
return cvSize( cvRound(max_height*aspect), max_height ); |
|
} |
|
|
|
#if defined (GTK_VERSION3) |
|
static void |
|
cvImageWidget_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width) |
|
{ |
|
g_return_if_fail (widget != NULL); |
|
g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); |
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); |
|
|
|
if(image_widget->original_image != NULL) { |
|
*minimal_width = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ? |
|
gdk_window_get_width(gtk_widget_get_window(widget)) : image_widget->original_image->cols; |
|
} |
|
else { |
|
*minimal_width = 320; |
|
} |
|
|
|
if(image_widget->scaled_image != NULL) { |
|
*natural_width = *minimal_width < image_widget->scaled_image->cols ? |
|
image_widget->scaled_image->cols : *minimal_width; |
|
} |
|
else { |
|
*natural_width = *minimal_width; |
|
} |
|
} |
|
|
|
static void |
|
cvImageWidget_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height) |
|
{ |
|
g_return_if_fail (widget != NULL); |
|
g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); |
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); |
|
|
|
if(image_widget->original_image != NULL) { |
|
*minimal_height = (image_widget->flags & CV_WINDOW_AUTOSIZE) != CV_WINDOW_AUTOSIZE ? |
|
gdk_window_get_height(gtk_widget_get_window(widget)) : image_widget->original_image->rows; |
|
} |
|
else { |
|
*minimal_height = 240; |
|
} |
|
|
|
if(image_widget->scaled_image != NULL) { |
|
*natural_height = *minimal_height < image_widget->scaled_image->rows ? |
|
image_widget->scaled_image->rows : *minimal_height; |
|
} |
|
else { |
|
*natural_height = *minimal_height; |
|
} |
|
} |
|
|
|
#else |
|
static void |
|
cvImageWidget_size_request (GtkWidget *widget, |
|
GtkRequisition *requisition) |
|
{ |
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); |
|
|
|
//printf("cvImageWidget_size_request "); |
|
// the case the first time cvShowImage called or when AUTOSIZE |
|
if( image_widget->original_image && |
|
((image_widget->flags & CV_WINDOW_AUTOSIZE) || |
|
(image_widget->flags & CV_WINDOW_NO_IMAGE))) |
|
{ |
|
//printf("original "); |
|
requisition->width = image_widget->original_image->cols; |
|
requisition->height = image_widget->original_image->rows; |
|
} |
|
// default case |
|
else if(image_widget->scaled_image){ |
|
//printf("scaled "); |
|
requisition->width = image_widget->scaled_image->cols; |
|
requisition->height = image_widget->scaled_image->rows; |
|
} |
|
// the case before cvShowImage called |
|
else{ |
|
//printf("default "); |
|
requisition->width = 320; |
|
requisition->height = 240; |
|
} |
|
//printf("%d %d\n",requisition->width, requisition->height); |
|
} |
|
#endif //GTK_VERSION3 |
|
|
|
static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){ |
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); |
|
|
|
//printf("cvImageWidget_set_size %d %d\n", max_width, max_height); |
|
|
|
// don't allow to set the size |
|
if(image_widget->flags & CV_WINDOW_AUTOSIZE) return; |
|
if(!image_widget->original_image) return; |
|
|
|
CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols, |
|
image_widget->original_image->rows, max_width, max_height ); |
|
|
|
if( image_widget->scaled_image && |
|
( image_widget->scaled_image->cols != scaled_image_size.width || |
|
image_widget->scaled_image->rows != scaled_image_size.height )) |
|
{ |
|
cvReleaseMat( &image_widget->scaled_image ); |
|
} |
|
if( !image_widget->scaled_image ){ |
|
image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 ); |
|
|
|
|
|
} |
|
assert( image_widget->scaled_image ); |
|
} |
|
|
|
static void |
|
cvImageWidget_size_allocate (GtkWidget *widget, |
|
GtkAllocation *allocation) |
|
{ |
|
CvImageWidget *image_widget; |
|
|
|
//printf("cvImageWidget_size_allocate\n"); |
|
g_return_if_fail (widget != NULL); |
|
g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); |
|
g_return_if_fail (allocation != NULL); |
|
|
|
#if defined (GTK_VERSION3) |
|
gtk_widget_set_allocation(widget, allocation); |
|
#else |
|
widget->allocation = *allocation; |
|
#endif //GTK_VERSION3 |
|
image_widget = CV_IMAGE_WIDGET (widget); |
|
|
|
|
|
if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){ |
|
// (re) allocated scaled image |
|
if( image_widget->flags & CV_WINDOW_NO_IMAGE ){ |
|
cvImageWidget_set_size( widget, image_widget->original_image->cols, |
|
image_widget->original_image->rows); |
|
} |
|
else{ |
|
cvImageWidget_set_size( widget, allocation->width, allocation->height ); |
|
} |
|
cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA ); |
|
} |
|
|
|
if (gtk_widget_get_realized (widget)) |
|
{ |
|
image_widget = CV_IMAGE_WIDGET (widget); |
|
|
|
if( image_widget->original_image && |
|
((image_widget->flags & CV_WINDOW_AUTOSIZE) || |
|
(image_widget->flags & CV_WINDOW_NO_IMAGE)) ) |
|
{ |
|
#if defined (GTK_VERSION3) |
|
allocation->width = image_widget->original_image->cols; |
|
allocation->height = image_widget->original_image->rows; |
|
gtk_widget_set_allocation(widget, allocation); |
|
#else |
|
widget->allocation.width = image_widget->original_image->cols; |
|
widget->allocation.height = image_widget->original_image->rows; |
|
#endif //GTK_VERSION3 |
|
gdk_window_move_resize( gtk_widget_get_window(widget), |
|
allocation->x, allocation->y, |
|
image_widget->original_image->cols, image_widget->original_image->rows ); |
|
if(image_widget->flags & CV_WINDOW_NO_IMAGE){ |
|
image_widget->flags &= ~CV_WINDOW_NO_IMAGE; |
|
gtk_widget_queue_resize( GTK_WIDGET(widget) ); |
|
} |
|
} |
|
else{ |
|
gdk_window_move_resize (gtk_widget_get_window(widget), |
|
allocation->x, allocation->y, |
|
allocation->width, allocation->height ); |
|
} |
|
} |
|
} |
|
|
|
#if defined (GTK_VERSION3) |
|
static void |
|
cvImageWidget_destroy (GtkWidget *object) |
|
#else |
|
static void |
|
cvImageWidget_destroy (GtkObject *object) |
|
#endif //GTK_VERSION3 |
|
{ |
|
CvImageWidget *image_widget; |
|
|
|
g_return_if_fail (object != NULL); |
|
g_return_if_fail (CV_IS_IMAGE_WIDGET (object)); |
|
|
|
image_widget = CV_IMAGE_WIDGET (object); |
|
|
|
cvReleaseMat( &image_widget->scaled_image ); |
|
cvReleaseMat( &image_widget->original_image ); |
|
|
|
#if defined (GTK_VERSION3) |
|
if (GTK_WIDGET_CLASS (parent_class)->destroy) |
|
(* GTK_WIDGET_CLASS (parent_class)->destroy) (object); |
|
#else |
|
if (GTK_OBJECT_CLASS (parent_class)->destroy) |
|
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object); |
|
#endif //GTK_VERSION3 |
|
} |
|
|
|
static void cvImageWidget_class_init (gpointer g_class, gpointer /*class_data*/) |
|
{ |
|
CvImageWidgetClass* klass = (CvImageWidgetClass*)g_class; |
|
#if defined (GTK_VERSION3) |
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
|
#else |
|
GtkObjectClass *object_class; |
|
GtkWidgetClass *widget_class; |
|
|
|
object_class = (GtkObjectClass*) klass; |
|
widget_class = (GtkWidgetClass*) klass; |
|
#endif //GTK_VERSION3 |
|
|
|
parent_class = GTK_WIDGET_CLASS( g_type_class_peek (gtk_widget_get_type ()) ); |
|
|
|
#if defined (GTK_VERSION3) |
|
widget_class->destroy = cvImageWidget_destroy; |
|
widget_class->get_preferred_width = cvImageWidget_get_preferred_width; |
|
widget_class->get_preferred_height = cvImageWidget_get_preferred_height; |
|
#else |
|
object_class->destroy = cvImageWidget_destroy; |
|
widget_class->size_request = cvImageWidget_size_request; |
|
#endif //GTK_VERSION3 |
|
|
|
widget_class->realize = cvImageWidget_realize; |
|
widget_class->size_allocate = cvImageWidget_size_allocate; |
|
widget_class->button_press_event = NULL; |
|
widget_class->button_release_event = NULL; |
|
widget_class->motion_notify_event = NULL; |
|
} |
|
|
|
static void |
|
cvImageWidget_init(GTypeInstance* instance, gpointer /*g_class*/) |
|
{ |
|
CvImageWidget* image_widget = (CvImageWidget*)instance; |
|
image_widget->original_image=0; |
|
image_widget->scaled_image=0; |
|
image_widget->flags=0; |
|
} |
|
|
|
GType cvImageWidget_get_type (void){ |
|
static GType image_type = 0; |
|
|
|
if (!image_type) |
|
{ |
|
image_type = g_type_register_static_simple( |
|
GTK_TYPE_WIDGET, |
|
(gchar*) "CvImageWidget", |
|
sizeof(CvImageWidgetClass), |
|
cvImageWidget_class_init, |
|
sizeof(CvImageWidget), |
|
cvImageWidget_init, |
|
(GTypeFlags)0 |
|
); |
|
} |
|
|
|
return image_type; |
|
} |
|
///////////////////////////////////////////////////////////////////////////// |
|
// End CvImageWidget |
|
///////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
struct CvWindow; |
|
|
|
struct CvUIBase { |
|
CvUIBase(int signature_) : signature(signature_) { } |
|
|
|
int signature; |
|
}; |
|
|
|
struct CvTrackbar : CvUIBase |
|
{ |
|
CvTrackbar(const char* trackbar_name) : |
|
CvUIBase(CV_TRACKBAR_MAGIC_VAL), |
|
widget(NULL), name(trackbar_name), |
|
parent(NULL), data(NULL), |
|
pos(0), maxval(0), minval(0), |
|
notify(NULL), notify2(NULL), userdata(NULL) |
|
{ |
|
// nothing |
|
} |
|
~CvTrackbar() |
|
{ |
|
// destroyed by parent window |
|
} |
|
|
|
GtkWidget* widget; |
|
std::string name; |
|
CvWindow* parent; |
|
int* data; |
|
int pos; |
|
int maxval; |
|
int minval; |
|
CvTrackbarCallback notify; |
|
CvTrackbarCallback2 notify2; |
|
void* userdata; |
|
}; |
|
|
|
|
|
struct CvWindow : CvUIBase |
|
{ |
|
CvWindow(const char* window_name) : |
|
CvUIBase(CV_WINDOW_MAGIC_VAL), |
|
widget(NULL), frame(NULL), paned(NULL), name(window_name), |
|
last_key(0), flags(0), status(0), |
|
on_mouse(NULL), on_mouse_param(NULL) |
|
#ifdef HAVE_OPENGL |
|
,useGl(false), glDrawCallback(NULL), glDrawData(NULL) |
|
#endif |
|
{ |
|
// nothing |
|
} |
|
~CvWindow(); |
|
|
|
GtkWidget* widget; |
|
GtkWidget* frame; |
|
GtkWidget* paned; |
|
std::string name; |
|
|
|
int last_key; |
|
int flags; |
|
int status;//0 normal, 1 fullscreen (YV) |
|
|
|
CvMouseCallback on_mouse; |
|
void* on_mouse_param; |
|
|
|
std::vector< Ptr<CvTrackbar> > trackbars; |
|
|
|
#ifdef HAVE_OPENGL |
|
bool useGl; |
|
|
|
CvOpenGlDrawCallback glDrawCallback; |
|
void* glDrawData; |
|
#endif |
|
}; |
|
|
|
|
|
static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data ); |
|
static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data ); |
|
static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ); |
|
static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ); |
|
|
|
#ifdef HAVE_GTHREAD |
|
int thread_started=0; |
|
static gpointer icvWindowThreadLoop(gpointer data); |
|
GMutex* last_key_mutex = NULL; |
|
GCond* cond_have_key = NULL; |
|
GThread* window_thread = NULL; |
|
#endif |
|
|
|
static cv::Mutex& getWindowMutex() |
|
{ |
|
static cv::Mutex* g_window_mutex = new cv::Mutex(); |
|
return *g_window_mutex; |
|
} |
|
|
|
static int last_key = -1; |
|
static std::vector< Ptr<CvWindow> > g_windows; |
|
|
|
CV_IMPL int cvInitSystem( int argc, char** argv ) |
|
{ |
|
static int wasInitialized = 0; |
|
|
|
// check initialization status |
|
if( !wasInitialized ) |
|
{ |
|
gtk_init( &argc, &argv ); |
|
setlocale(LC_NUMERIC,"C"); |
|
|
|
#ifdef HAVE_OPENGL |
|
gtk_gl_init(&argc, &argv); |
|
#endif |
|
|
|
wasInitialized = 1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
CV_IMPL int cvStartWindowThread(){ |
|
#ifdef HAVE_GTHREAD |
|
cvInitSystem(0,NULL); |
|
if (!thread_started) |
|
{ |
|
if (!g_thread_supported ()) { |
|
/* the GThread system wasn't inited, so init it */ |
|
g_thread_init(NULL); |
|
} |
|
|
|
(void)getWindowMutex(); // force mutex initialization |
|
|
|
// protects the 'last key pressed' variable |
|
last_key_mutex = g_mutex_new(); |
|
|
|
// conditional that indicates a key has been pressed |
|
cond_have_key = g_cond_new(); |
|
|
|
#if !GLIB_CHECK_VERSION(2, 32, 0) |
|
// this is the window update thread |
|
window_thread = g_thread_create(icvWindowThreadLoop, |
|
NULL, TRUE, NULL); |
|
#else |
|
window_thread = g_thread_new("OpenCV window update", icvWindowThreadLoop, NULL); |
|
#endif |
|
} |
|
thread_started = window_thread!=NULL; |
|
return thread_started; |
|
#else |
|
return 0; |
|
#endif |
|
} |
|
|
|
#ifdef HAVE_GTHREAD |
|
gpointer icvWindowThreadLoop(gpointer /*data*/) |
|
{ |
|
while(1){ |
|
{ |
|
cv::AutoLock lock(getWindowMutex()); |
|
gtk_main_iteration_do(FALSE); |
|
} |
|
|
|
// little sleep |
|
g_usleep(500); |
|
|
|
g_thread_yield(); |
|
} |
|
return NULL; |
|
} |
|
|
|
#endif |
|
|
|
#define CV_LOCK_MUTEX() cv::AutoLock lock(getWindowMutex()) |
|
|
|
static CvWindow* icvFindWindowByName( const char* name ) |
|
{ |
|
for(size_t i = 0; i < g_windows.size(); ++i) |
|
{ |
|
CvWindow* window = g_windows[i].get(); |
|
if (window->name == name) |
|
return window; |
|
} |
|
return NULL; |
|
} |
|
|
|
static CvWindow* icvWindowByWidget( GtkWidget* widget ) |
|
{ |
|
for (size_t i = 0; i < g_windows.size(); ++i) |
|
{ |
|
CvWindow* window = g_windows[i].get(); |
|
if (window->widget == widget || window->frame == widget || window->paned == widget) |
|
return window; |
|
} |
|
return NULL; |
|
} |
|
|
|
CvRect cvGetWindowRect_GTK(const char* name) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
CV_Error( CV_StsNullPtr, "NULL window" ); |
|
|
|
gint wx, wy; |
|
#ifdef HAVE_OPENGL |
|
if (window->useGl) { |
|
gtk_widget_translate_coordinates(window->widget, gtk_widget_get_toplevel(window->widget), 0, 0, &wx, &wy); |
|
return cvRect(wx, wy, window->widget->allocation.width, window->widget->allocation.height); |
|
} |
|
#endif |
|
|
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget ); |
|
gtk_widget_translate_coordinates(&image_widget->widget, gtk_widget_get_toplevel(&image_widget->widget), 0, 0, &wx, &wy); |
|
if (image_widget->scaled_image) { |
|
#if defined (GTK_VERSION3) |
|
return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(window->widget)), |
|
MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(window->widget))); |
|
#else |
|
return cvRect(wx, wy, MIN(image_widget->scaled_image->cols, window->widget->allocation.width), |
|
MIN(image_widget->scaled_image->rows, window->widget->allocation.height)); |
|
#endif //GTK_VERSION3 |
|
} else if (image_widget->original_image) { |
|
#if defined (GTK_VERSION3) |
|
return cvRect(wx, wy, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(window->widget)), |
|
MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(window->widget))); |
|
#else |
|
return cvRect(wx, wy, MIN(image_widget->original_image->cols, window->widget->allocation.width), |
|
MIN(image_widget->original_image->rows, window->widget->allocation.height)); |
|
#endif //GTK_VERSION3 |
|
} |
|
|
|
return cvRect(-1, -1, -1, -1); |
|
} |
|
|
|
double cvGetModeWindow_GTK(const char* name)//YV |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
CV_Error( CV_StsNullPtr, "NULL window" ); |
|
|
|
double result = window->status; |
|
return result; |
|
} |
|
|
|
|
|
void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if( !window ) |
|
CV_Error( CV_StsNullPtr, "NULL window" ); |
|
|
|
if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set |
|
return; |
|
|
|
//so easy to do fullscreen here, Linux rocks ! |
|
|
|
if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL) |
|
{ |
|
gtk_window_unfullscreen(GTK_WINDOW(window->frame)); |
|
window->status=CV_WINDOW_NORMAL; |
|
return; |
|
} |
|
|
|
if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) |
|
{ |
|
gtk_window_fullscreen(GTK_WINDOW(window->frame)); |
|
window->status=CV_WINDOW_FULLSCREEN; |
|
return; |
|
} |
|
} |
|
|
|
void cv::setWindowTitle(const String& winname, const String& title) |
|
{ |
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(winname.c_str()); |
|
|
|
if (!window) |
|
{ |
|
namedWindow(winname); |
|
window = icvFindWindowByName(winname.c_str()); |
|
CV_Assert(window); |
|
} |
|
|
|
gtk_window_set_title(GTK_WINDOW(window->frame), title.c_str()); |
|
} |
|
|
|
double cvGetPropWindowAutoSize_GTK(const char* name) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
return -1; // keep silence here |
|
|
|
double result = window->flags & CV_WINDOW_AUTOSIZE; |
|
return result; |
|
} |
|
|
|
double cvGetRatioWindow_GTK(const char* name) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
return -1; // keep silence here |
|
|
|
#if defined (GTK_VERSION3) |
|
double result = static_cast<double>( |
|
gtk_widget_get_allocated_width(window->widget)) / gtk_widget_get_allocated_height(window->widget); |
|
#else |
|
double result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height; |
|
#endif // GTK_VERSION3 |
|
return result; |
|
} |
|
|
|
double cvGetOpenGlProp_GTK(const char* name) |
|
{ |
|
#ifdef HAVE_OPENGL |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
return -1; // keep silence here |
|
|
|
double result = window->useGl; |
|
return result; |
|
#else |
|
(void)name; |
|
return -1; |
|
#endif |
|
} |
|
|
|
|
|
// OpenGL support |
|
|
|
#ifdef HAVE_OPENGL |
|
|
|
namespace |
|
{ |
|
void createGlContext(CvWindow* window) |
|
{ |
|
GdkGLConfig* glconfig; |
|
|
|
// Try double-buffered visual |
|
glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE)); |
|
if (!glconfig) |
|
CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" ); |
|
|
|
// Set OpenGL-capability to the widget |
|
if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE)) |
|
CV_Error( CV_OpenGlApiCallError, "Can't Create A GL Device Context" ); |
|
|
|
window->useGl = true; |
|
} |
|
|
|
void drawGl(CvWindow* window) |
|
{ |
|
GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget); |
|
GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget); |
|
|
|
if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) |
|
CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); |
|
|
|
glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height); |
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|
|
|
if (window->glDrawCallback) |
|
window->glDrawCallback(window->glDrawData); |
|
|
|
if (gdk_gl_drawable_is_double_buffered (gldrawable)) |
|
gdk_gl_drawable_swap_buffers(gldrawable); |
|
else |
|
glFlush(); |
|
|
|
gdk_gl_drawable_gl_end(gldrawable); |
|
} |
|
} |
|
|
|
#endif // HAVE_OPENGL |
|
|
|
#if defined (GTK_VERSION3) |
|
static gboolean cvImageWidget_draw(GtkWidget* widget, cairo_t *cr, gpointer data) |
|
{ |
|
#ifdef HAVE_OPENGL |
|
CvWindow* window = (CvWindow*)data; |
|
|
|
if (window->useGl) |
|
{ |
|
drawGl(window); |
|
return TRUE; |
|
} |
|
#else |
|
(void)data; |
|
#endif |
|
|
|
CvImageWidget *image_widget = NULL; |
|
GdkPixbuf *pixbuf = NULL; |
|
|
|
g_return_val_if_fail (widget != NULL, FALSE); |
|
g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE); |
|
|
|
image_widget = CV_IMAGE_WIDGET (widget); |
|
|
|
if( image_widget->scaled_image ){ |
|
// center image in available region |
|
#if defined (GTK_VERSION3) |
|
int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2; |
|
int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2; |
|
#else |
|
int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; |
|
int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; |
|
#endif //GTK_VERSION3 |
|
|
|
#if defined (GTK_VERSION3) |
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->scaled_image->cols, gtk_widget_get_allocated_width(widget)), |
|
MIN(image_widget->scaled_image->rows, gtk_widget_get_allocated_height(widget)), |
|
image_widget->scaled_image->step, NULL, NULL); |
|
#else |
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->scaled_image->cols, widget->allocation.width), |
|
MIN(image_widget->scaled_image->rows, widget->allocation.height), |
|
image_widget->scaled_image->step, NULL, NULL); |
|
#endif //GTK_VERSION3 |
|
|
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0); |
|
} |
|
else if( image_widget->original_image ){ |
|
#if defined (GTK_VERSION3) |
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->original_image->cols, gtk_widget_get_allocated_width(widget)), |
|
MIN(image_widget->original_image->rows, gtk_widget_get_allocated_height(widget)), |
|
image_widget->original_image->step, NULL, NULL); |
|
#else |
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->original_image->cols, widget->allocation.width), |
|
MIN(image_widget->original_image->rows, widget->allocation.height), |
|
image_widget->original_image->step, NULL, NULL); |
|
#endif //GTK_VERSION3 |
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
|
} |
|
|
|
cairo_paint(cr); |
|
if(pixbuf) |
|
g_object_unref(pixbuf); |
|
return TRUE; |
|
} |
|
|
|
#else |
|
static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data) |
|
{ |
|
#ifdef HAVE_OPENGL |
|
CvWindow* window = (CvWindow*)data; |
|
|
|
if (window->useGl) |
|
{ |
|
drawGl(window); |
|
return TRUE; |
|
} |
|
#else |
|
(void)data; |
|
#endif |
|
|
|
CvImageWidget *image_widget = NULL; |
|
cairo_t *cr = NULL; |
|
GdkPixbuf *pixbuf = NULL; |
|
|
|
g_return_val_if_fail (widget != NULL, FALSE); |
|
g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE); |
|
g_return_val_if_fail (event != NULL, FALSE); |
|
|
|
if (event->count > 0) |
|
return FALSE; |
|
|
|
cr = gdk_cairo_create(widget->window); |
|
image_widget = CV_IMAGE_WIDGET (widget); |
|
|
|
if( image_widget->scaled_image ){ |
|
// center image in available region |
|
int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; |
|
int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; |
|
|
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->scaled_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->scaled_image->cols, widget->allocation.width), |
|
MIN(image_widget->scaled_image->rows, widget->allocation.height), |
|
image_widget->scaled_image->step, NULL, NULL); |
|
|
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, x0, y0); |
|
} |
|
else if( image_widget->original_image ){ |
|
pixbuf = gdk_pixbuf_new_from_data(image_widget->original_image->data.ptr, GDK_COLORSPACE_RGB, false, |
|
8, MIN(image_widget->original_image->cols, widget->allocation.width), |
|
MIN(image_widget->original_image->rows, widget->allocation.height), |
|
image_widget->original_image->step, NULL, NULL); |
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
|
} |
|
|
|
cairo_paint(cr); |
|
if(pixbuf) |
|
g_object_unref(pixbuf); |
|
cairo_destroy(cr); |
|
return TRUE; |
|
} |
|
#endif //GTK_VERSION3 |
|
|
|
CV_IMPL int cvNamedWindow( const char* name, int flags ) |
|
{ |
|
cvInitSystem(name ? 1 : 0,(char**)&name); |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
// Check the name in the storage |
|
if (icvFindWindowByName(name)) |
|
{ |
|
return 1; |
|
} |
|
|
|
Ptr<CvWindow> window = makePtr<CvWindow>(name); |
|
window->flags = flags; |
|
window->status = CV_WINDOW_NORMAL;//YV |
|
|
|
window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL ); |
|
|
|
window->paned = gtk_vbox_new( FALSE, 0 ); |
|
window->widget = cvImageWidgetNew( flags ); |
|
gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 ); |
|
gtk_widget_show( window->widget ); |
|
gtk_container_add( GTK_CONTAINER(window->frame), window->paned ); |
|
gtk_widget_show( window->paned ); |
|
|
|
#ifndef HAVE_OPENGL |
|
if (flags & CV_WINDOW_OPENGL) |
|
CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" ); |
|
#else |
|
if (flags & CV_WINDOW_OPENGL) |
|
createGlContext(window); |
|
|
|
window->glDrawCallback = 0; |
|
window->glDrawData = 0; |
|
#endif |
|
|
|
// |
|
// configure event handlers |
|
// TODO -- move this to CvImageWidget ? |
|
g_signal_connect( window->frame, "key-press-event", |
|
G_CALLBACK(icvOnKeyPress), window ); |
|
g_signal_connect( window->widget, "button-press-event", |
|
G_CALLBACK(icvOnMouse), window ); |
|
g_signal_connect( window->widget, "button-release-event", |
|
G_CALLBACK(icvOnMouse), window ); |
|
g_signal_connect( window->widget, "motion-notify-event", |
|
G_CALLBACK(icvOnMouse), window ); |
|
g_signal_connect( window->widget, "scroll-event", |
|
G_CALLBACK(icvOnMouse), window ); |
|
g_signal_connect( window->frame, "delete-event", |
|
G_CALLBACK(icvOnClose), window ); |
|
#if defined(GTK_VERSION3) |
|
g_signal_connect( window->widget, "draw", |
|
G_CALLBACK(cvImageWidget_draw), window ); |
|
#else |
|
g_signal_connect( window->widget, "expose-event", |
|
G_CALLBACK(cvImageWidget_expose), window ); |
|
#endif //GTK_VERSION3 |
|
|
|
|
|
#if defined(GTK_VERSION3_4) |
|
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) ; |
|
#else |
|
gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK) ; |
|
#endif //GTK_VERSION3_4 |
|
|
|
gtk_widget_show( window->frame ); |
|
gtk_window_set_title( GTK_WINDOW(window->frame), name ); |
|
|
|
g_windows.push_back(window); |
|
|
|
bool b_nautosize = ((flags & CV_WINDOW_AUTOSIZE) == 0); |
|
gtk_window_set_resizable( GTK_WINDOW(window->frame), b_nautosize ); |
|
|
|
// allow window to be resized |
|
if( b_nautosize ){ |
|
GdkGeometry geometry; |
|
geometry.min_width = 50; |
|
geometry.min_height = 50; |
|
gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ), |
|
&geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE)); |
|
} |
|
|
|
#ifdef HAVE_OPENGL |
|
if (window->useGl) |
|
cvSetOpenGlContext(name); |
|
#endif |
|
|
|
return 1; |
|
} |
|
|
|
|
|
#ifdef HAVE_OPENGL |
|
|
|
CV_IMPL void cvSetOpenGlContext(const char* name) |
|
{ |
|
GdkGLContext* glcontext; |
|
GdkGLDrawable* gldrawable; |
|
|
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
CV_Error( CV_StsNullPtr, "NULL window" ); |
|
|
|
if (!window->useGl) |
|
CV_Error( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); |
|
|
|
glcontext = gtk_widget_get_gl_context(window->widget); |
|
gldrawable = gtk_widget_get_gl_drawable(window->widget); |
|
|
|
if (!gdk_gl_drawable_make_current(gldrawable, glcontext)) |
|
CV_Error( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); |
|
} |
|
|
|
CV_IMPL void cvUpdateWindow(const char* name) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if (!window) |
|
return; |
|
|
|
// window does not refresh without this |
|
gtk_widget_queue_draw( GTK_WIDGET(window->widget) ); |
|
} |
|
|
|
CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if( !window ) |
|
return; |
|
|
|
if (!window->useGl) |
|
CV_Error( CV_OpenGlNotSupported, "Window was created without OpenGL context" ); |
|
|
|
window->glDrawCallback = callback; |
|
window->glDrawData = userdata; |
|
} |
|
|
|
#endif // HAVE_OPENGL |
|
|
|
|
|
|
|
CvWindow::~CvWindow() |
|
{ |
|
gtk_widget_destroy(frame); |
|
} |
|
|
|
static void checkLastWindow() |
|
{ |
|
// if last window... |
|
if (g_windows.empty()) |
|
{ |
|
#ifdef HAVE_GTHREAD |
|
if( thread_started ) |
|
{ |
|
// send key press signal to jump out of any waiting cvWaitKey's |
|
g_cond_broadcast( cond_have_key ); |
|
} |
|
else |
|
{ |
|
#endif |
|
// Some GTK+ modules (like the Unity module) use GDBusConnection, |
|
// which has a habit of postponing cleanup by performing it via |
|
// idle sources added to the main loop. Since this was the last window, |
|
// we can assume that no event processing is going to happen in the |
|
// nearest future, so we should force that cleanup (by handling all pending |
|
// events) while we still have the chance. |
|
// This is not needed if thread_started is true, because the background |
|
// thread will process events continuously. |
|
while( gtk_events_pending() ) |
|
gtk_main_iteration(); |
|
#ifdef HAVE_GTHREAD |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
static void icvDeleteWindow( CvWindow* window ) |
|
{ |
|
bool found = false; |
|
for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin(); |
|
i != g_windows.end(); ++i) |
|
{ |
|
if (i->get() == window) |
|
{ |
|
g_windows.erase(i); |
|
found = true; |
|
break; |
|
} |
|
} |
|
CV_Assert(found && "Can't destroy non-registered window"); |
|
|
|
checkLastWindow(); |
|
} |
|
|
|
CV_IMPL void cvDestroyWindow( const char* name ) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
bool found = false; |
|
for (std::vector< Ptr<CvWindow> >::iterator i = g_windows.begin(); |
|
i != g_windows.end(); ++i) |
|
{ |
|
if (i->get()->name == name) |
|
{ |
|
g_windows.erase(i); |
|
found = true; |
|
break; |
|
} |
|
} |
|
CV_Assert(found && "Can't destroy non-registered window"); |
|
|
|
checkLastWindow(); |
|
} |
|
|
|
|
|
CV_IMPL void |
|
cvDestroyAllWindows( void ) |
|
{ |
|
CV_LOCK_MUTEX(); |
|
|
|
g_windows.clear(); |
|
checkLastWindow(); |
|
} |
|
|
|
// CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){ |
|
// CvSize window_size; |
|
// GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame ); |
|
// gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window), |
|
// &window_size.width, &window_size.height ); |
|
|
|
// window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width; |
|
// window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height; |
|
|
|
// return window_size; |
|
// } |
|
|
|
CV_IMPL void |
|
cvShowImage( const char* name, const CvArr* arr ) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if(!window) |
|
{ |
|
cvNamedWindow(name, 1); |
|
window = icvFindWindowByName(name); |
|
} |
|
CV_Assert(window); |
|
|
|
if (arr) |
|
{ |
|
#ifdef HAVE_OPENGL |
|
if (window->useGl) |
|
{ |
|
cv::imshow(name, cv::cvarrToMat(arr)); |
|
return; |
|
} |
|
#endif |
|
|
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget ); |
|
cvImageWidgetSetImage( image_widget, arr ); |
|
} |
|
} |
|
|
|
CV_IMPL void cvResizeWindow(const char* name, int width, int height ) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if(!window) |
|
return; |
|
|
|
CvImageWidget* image_widget = CV_IMAGE_WIDGET( window->widget ); |
|
//if(image_widget->flags & CV_WINDOW_AUTOSIZE) |
|
//EXIT; |
|
|
|
gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 ); |
|
gtk_window_resize( GTK_WINDOW(window->frame), width, height ); |
|
|
|
// disable initial resize since presumably user wants to keep |
|
// this window size |
|
image_widget->flags &= ~CV_WINDOW_NO_IMAGE; |
|
} |
|
|
|
|
|
CV_IMPL void cvMoveWindow( const char* name, int x, int y ) |
|
{ |
|
CV_Assert(name && "NULL name string"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(name); |
|
if(!window) |
|
return; |
|
|
|
gtk_window_move( GTK_WINDOW(window->frame), x, y ); |
|
} |
|
|
|
|
|
static CvTrackbar* |
|
icvFindTrackbarByName( const CvWindow* window, const char* name ) |
|
{ |
|
for (size_t i = 0; i < window->trackbars.size(); ++i) |
|
{ |
|
CvTrackbar* trackbar = window->trackbars[i].get(); |
|
if (trackbar->name == name) |
|
return trackbar; |
|
} |
|
return NULL; |
|
} |
|
|
|
static int |
|
icvCreateTrackbar( const char* trackbar_name, const char* window_name, |
|
int* val, int count, CvTrackbarCallback on_notify, |
|
CvTrackbarCallback2 on_notify2, void* userdata ) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
CV_Assert(trackbar_name && "NULL trackbar name"); |
|
|
|
if( count <= 0 ) |
|
CV_Error( CV_StsOutOfRange, "Bad trackbar maximal value" ); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if(!window) |
|
return 0; |
|
|
|
CvTrackbar* trackbar = icvFindTrackbarByName(window, trackbar_name); |
|
if (!trackbar) |
|
{ |
|
Ptr<CvTrackbar> trackbar_ = makePtr<CvTrackbar>(trackbar_name); |
|
trackbar = trackbar_.get(); |
|
trackbar->parent = window; |
|
window->trackbars.push_back(trackbar_); |
|
|
|
GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 ); |
|
GtkWidget* hscale_label = gtk_label_new( trackbar_name ); |
|
GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 ); |
|
gtk_scale_set_digits( GTK_SCALE(hscale), 0 ); |
|
//gtk_scale_set_value_pos( hscale, GTK_POS_TOP ); |
|
gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE ); |
|
|
|
trackbar->widget = hscale; |
|
gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 ); |
|
gtk_widget_show( hscale_label ); |
|
gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 ); |
|
gtk_widget_show( hscale ); |
|
gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 ); |
|
gtk_widget_show( hscale_box ); |
|
} |
|
|
|
if( val ) |
|
{ |
|
int value = *val; |
|
if( value < 0 ) |
|
value = 0; |
|
if( value > count ) |
|
value = count; |
|
gtk_range_set_value( GTK_RANGE(trackbar->widget), value ); |
|
trackbar->pos = value; |
|
trackbar->data = val; |
|
} |
|
|
|
trackbar->maxval = count; |
|
trackbar->notify = on_notify; |
|
trackbar->notify2 = on_notify2; |
|
trackbar->userdata = userdata; |
|
g_signal_connect( trackbar->widget, "value-changed", |
|
G_CALLBACK(icvOnTrackbar), trackbar ); |
|
|
|
// queue a widget resize to trigger a window resize to |
|
// compensate for the addition of trackbars |
|
gtk_widget_queue_resize( GTK_WIDGET(window->widget) ); |
|
|
|
return 1; |
|
} |
|
|
|
|
|
CV_IMPL int |
|
cvCreateTrackbar( const char* trackbar_name, const char* window_name, |
|
int* val, int count, CvTrackbarCallback on_notify ) |
|
{ |
|
return icvCreateTrackbar(trackbar_name, window_name, val, count, |
|
on_notify, 0, 0); |
|
} |
|
|
|
|
|
CV_IMPL int |
|
cvCreateTrackbar2( const char* trackbar_name, const char* window_name, |
|
int* val, int count, CvTrackbarCallback2 on_notify2, |
|
void* userdata ) |
|
{ |
|
return icvCreateTrackbar(trackbar_name, window_name, val, count, |
|
0, on_notify2, userdata); |
|
} |
|
|
|
|
|
CV_IMPL void |
|
cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param ) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if (!window) |
|
return; |
|
|
|
window->on_mouse = on_mouse; |
|
window->on_mouse_param = param; |
|
} |
|
|
|
|
|
CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
CV_Assert(trackbar_name && "NULL trackbar name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if (!window) |
|
return -1; |
|
|
|
CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name); |
|
if (!trackbar) |
|
return -1; |
|
|
|
return trackbar->pos; |
|
} |
|
|
|
|
|
CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
CV_Assert(trackbar_name && "NULL trackbar name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if(!window) |
|
return; |
|
|
|
CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name); |
|
if( trackbar ) |
|
{ |
|
if( pos < trackbar->minval ) |
|
pos = trackbar->minval; |
|
|
|
if( pos > trackbar->maxval ) |
|
pos = trackbar->maxval; |
|
} |
|
else |
|
{ |
|
CV_Error( CV_StsNullPtr, "No trackbar found" ); |
|
} |
|
|
|
gtk_range_set_value( GTK_RANGE(trackbar->widget), pos ); |
|
} |
|
|
|
|
|
CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
CV_Assert(trackbar_name && "NULL trackbar name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if(!window) |
|
return; |
|
|
|
CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name); |
|
if(!trackbar) |
|
return; |
|
|
|
trackbar->maxval = maxval; |
|
if (trackbar->maxval >= trackbar->minval) |
|
gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval); |
|
} |
|
|
|
|
|
CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
CV_Assert(trackbar_name && "NULL trackbar name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if(!window) |
|
return; |
|
|
|
CvTrackbar* trackbar = icvFindTrackbarByName(window,trackbar_name); |
|
if(!trackbar) |
|
return; |
|
|
|
trackbar->minval = minval; |
|
if (trackbar->maxval >= trackbar->minval) |
|
gtk_range_set_range(GTK_RANGE(trackbar->widget), trackbar->minval, trackbar->maxval); |
|
} |
|
|
|
|
|
CV_IMPL void* cvGetWindowHandle( const char* window_name ) |
|
{ |
|
CV_Assert(window_name && "NULL window name"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvFindWindowByName(window_name); |
|
if(!window) |
|
return NULL; |
|
|
|
return (void*)window->widget; |
|
} |
|
|
|
|
|
CV_IMPL const char* cvGetWindowName( void* window_handle ) |
|
{ |
|
CV_Assert(window_handle && "NULL window handle"); |
|
|
|
CV_LOCK_MUTEX(); |
|
|
|
CvWindow* window = icvWindowByWidget( (GtkWidget*)window_handle ); |
|
if (window) |
|
return window->name.c_str(); |
|
|
|
return ""; // FIXME: NULL? |
|
} |
|
|
|
static GtkFileFilter* icvMakeGtkFilter(const char* name, const char* patterns, GtkFileFilter* images) |
|
{ |
|
GtkFileFilter* filter = gtk_file_filter_new(); |
|
gtk_file_filter_set_name(filter, name); |
|
|
|
while(patterns[0]) |
|
{ |
|
gtk_file_filter_add_pattern(filter, patterns); |
|
gtk_file_filter_add_pattern(images, patterns); |
|
patterns += strlen(patterns) + 1; |
|
} |
|
|
|
return filter; |
|
} |
|
|
|
static void icvShowSaveAsDialog(GtkWidget* widget, CvWindow* window) |
|
{ |
|
if (!window || !widget) |
|
return; |
|
|
|
CvImageWidget* image_widget = CV_IMAGE_WIDGET(window->widget); |
|
if (!image_widget || !image_widget->original_image) |
|
return; |
|
|
|
GtkWidget* dialog = gtk_file_chooser_dialog_new("Save As...", |
|
GTK_WINDOW(widget), |
|
GTK_FILE_CHOOSER_ACTION_SAVE, |
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, |
|
NULL); |
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); |
|
|
|
cv::String sname = gtk_window_get_title(GTK_WINDOW(window->frame)); |
|
sname = sname.substr(sname.find_last_of("\\/") + 1) + ".png"; |
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), sname.c_str()); |
|
|
|
GtkFileFilter* filter_all = gtk_file_filter_new(); |
|
gtk_file_filter_set_name(filter_all, "All Files"); |
|
gtk_file_filter_add_pattern(filter_all, "*"); |
|
|
|
GtkFileFilter* filter_images = gtk_file_filter_new(); |
|
gtk_file_filter_set_name(filter_images, "All Images"); |
|
|
|
GtkFileFilter* file_filters[] = { |
|
icvMakeGtkFilter("Portable Network Graphics files (*.png)", "*.png\0", filter_images), |
|
icvMakeGtkFilter("JPEG files (*.jpeg;*.jpg;*.jpe)", "*.jpeg\0*.jpg\0*.jpe\0", filter_images), |
|
icvMakeGtkFilter("Windows bitmap (*.bmp;*.dib)", "*.bmp\0*.dib\0", filter_images), |
|
icvMakeGtkFilter("TIFF Files (*.tiff;*.tif)", "*.tiff\0*.tif\0", filter_images), |
|
icvMakeGtkFilter("JPEG-2000 files (*.jp2)", "*.jp2\0", filter_images), |
|
icvMakeGtkFilter("WebP files (*.webp)", "*.webp\0", filter_images), |
|
icvMakeGtkFilter("Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)", "*.pbm\0*.pgm\0*.ppm\0*.pxm\0*.pnm\0", filter_images), |
|
icvMakeGtkFilter("OpenEXR Image files (*.exr)", "*.exr\0", filter_images), |
|
icvMakeGtkFilter("Radiance HDR (*.hdr;*.pic)", "*.hdr\0*.pic\0", filter_images), |
|
icvMakeGtkFilter("Sun raster files (*.sr;*.ras)", "*.sr\0*.ras\0", filter_images), |
|
filter_images, |
|
filter_all |
|
}; |
|
|
|
for (size_t idx = 0; idx < sizeof(file_filters)/sizeof(file_filters[0]); ++idx) |
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), file_filters[idx]); // filter ownership is transferred to dialog |
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter_images); |
|
|
|
cv::String filename; |
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) |
|
{ |
|
char* fname = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); |
|
filename = fname; |
|
g_free(fname); |
|
} |
|
gtk_widget_destroy(dialog); |
|
|
|
if (!filename.empty()) |
|
{ |
|
cv::Mat bgr; |
|
cv::cvtColor(cv::cvarrToMat(image_widget->original_image), bgr, cv::COLOR_RGB2BGR); |
|
cv::imwrite(filename, bgr); |
|
} |
|
} |
|
|
|
#if defined (GTK_VERSION3) |
|
#define GDK_Escape GDK_KEY_Escape |
|
#define GDK_Return GDK_KEY_Return |
|
#define GDK_Linefeed GDK_KEY_Linefeed |
|
#define GDK_Tab GDK_KEY_Tab |
|
#define GDK_s GDK_KEY_s |
|
#define GDK_S GDK_KEY_S |
|
#endif //GTK_VERSION3 |
|
|
|
static gboolean icvOnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer user_data) |
|
{ |
|
int code = 0; |
|
|
|
if ( BIT_ALLIN(event->state, GDK_CONTROL_MASK) && (event->keyval == GDK_s || event->keyval == GDK_S)) |
|
{ |
|
try |
|
{ |
|
icvShowSaveAsDialog(widget, (CvWindow*)user_data); |
|
} |
|
catch(...) |
|
{ |
|
// suppress all exceptions here |
|
} |
|
} |
|
|
|
switch( event->keyval ) |
|
{ |
|
case GDK_Escape: |
|
code = 27; |
|
break; |
|
case GDK_Return: |
|
case GDK_Linefeed: |
|
code = 13; |
|
break; |
|
case GDK_Tab: |
|
code = '\t'; |
|
break; |
|
default: |
|
code = event->keyval; |
|
} |
|
|
|
code |= event->state << 16; |
|
|
|
#ifdef HAVE_GTHREAD |
|
if(thread_started) |
|
{ |
|
g_mutex_lock(last_key_mutex); |
|
last_key = code; |
|
// signal any waiting threads |
|
g_cond_broadcast(cond_have_key); |
|
g_mutex_unlock(last_key_mutex); |
|
} |
|
else |
|
#endif |
|
{ |
|
last_key = code; |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
|
|
static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ) |
|
{ |
|
int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget))); |
|
CvTrackbar* trackbar = (CvTrackbar*)user_data; |
|
|
|
if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL && |
|
trackbar->widget == widget ) |
|
{ |
|
trackbar->pos = pos; |
|
if( trackbar->data ) |
|
*trackbar->data = pos; |
|
if( trackbar->notify2 ) |
|
trackbar->notify2(pos, trackbar->userdata); |
|
else if( trackbar->notify ) |
|
trackbar->notify(pos); |
|
} |
|
} |
|
|
|
static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data ) |
|
{ |
|
CvWindow* window = (CvWindow*)user_data; |
|
if( window->signature == CV_WINDOW_MAGIC_VAL && |
|
window->frame == widget ) |
|
{ |
|
icvDeleteWindow(window); |
|
} |
|
return TRUE; |
|
} |
|
|
|
|
|
static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ) |
|
{ |
|
// TODO move this logic to CvImageWidget |
|
CvWindow* window = (CvWindow*)user_data; |
|
CvPoint2D32f pt32f = {-1., -1.}; |
|
CvPoint pt = {-1,-1}; |
|
int cv_event = -1, state = 0, flags = 0; |
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); |
|
|
|
if( window->signature != CV_WINDOW_MAGIC_VAL || |
|
window->widget != widget || !window->widget || |
|
!window->on_mouse /*|| !image_widget->original_image*/) |
|
return FALSE; |
|
|
|
if( event->type == GDK_MOTION_NOTIFY ) |
|
{ |
|
GdkEventMotion* event_motion = (GdkEventMotion*)event; |
|
|
|
cv_event = CV_EVENT_MOUSEMOVE; |
|
pt32f.x = cvRound(event_motion->x); |
|
pt32f.y = cvRound(event_motion->y); |
|
state = event_motion->state; |
|
} |
|
else if( event->type == GDK_BUTTON_PRESS || |
|
event->type == GDK_BUTTON_RELEASE || |
|
event->type == GDK_2BUTTON_PRESS ) |
|
{ |
|
GdkEventButton* event_button = (GdkEventButton*)event; |
|
pt32f.x = cvRound(event_button->x); |
|
pt32f.y = cvRound(event_button->y); |
|
|
|
|
|
if( event_button->type == GDK_BUTTON_PRESS ) |
|
{ |
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN : |
|
event_button->button == 2 ? CV_EVENT_MBUTTONDOWN : |
|
event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0; |
|
} |
|
else if( event_button->type == GDK_BUTTON_RELEASE ) |
|
{ |
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP : |
|
event_button->button == 2 ? CV_EVENT_MBUTTONUP : |
|
event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0; |
|
} |
|
else if( event_button->type == GDK_2BUTTON_PRESS ) |
|
{ |
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK : |
|
event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK : |
|
event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0; |
|
} |
|
state = event_button->state; |
|
} |
|
else if( event->type == GDK_SCROLL ) |
|
{ |
|
#if defined(GTK_VERSION3_4) |
|
// NOTE: in current implementation doesn't possible to put into callback function delta_x and delta_y separetely |
|
double delta = (event->scroll.delta_x + event->scroll.delta_y); |
|
cv_event = (event->scroll.delta_y!=0) ? CV_EVENT_MOUSEHWHEEL : CV_EVENT_MOUSEWHEEL; |
|
#else |
|
cv_event = CV_EVENT_MOUSEWHEEL; |
|
#endif //GTK_VERSION3_4 |
|
|
|
state = event->scroll.state; |
|
|
|
switch(event->scroll.direction) { |
|
#if defined(GTK_VERSION3_4) |
|
case GDK_SCROLL_SMOOTH: flags |= (((int)delta << 16)); |
|
break; |
|
#endif //GTK_VERSION3_4 |
|
case GDK_SCROLL_LEFT: cv_event = CV_EVENT_MOUSEHWHEEL; |
|
/* FALLTHRU */ |
|
case GDK_SCROLL_UP: flags |= ~0xffff; |
|
break; |
|
case GDK_SCROLL_RIGHT: cv_event = CV_EVENT_MOUSEHWHEEL; |
|
/* FALLTHRU */ |
|
case GDK_SCROLL_DOWN: flags |= (((int)1 << 16)); |
|
break; |
|
default: ; |
|
}; |
|
} |
|
|
|
if( cv_event >= 0 ) |
|
{ |
|
// scale point if image is scaled |
|
if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && |
|
image_widget->original_image && |
|
image_widget->scaled_image ) |
|
{ |
|
// image origin is not necessarily at (0,0) |
|
#if defined (GTK_VERSION3) |
|
int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2; |
|
int y0 = (gtk_widget_get_allocated_height(widget) - image_widget->scaled_image->rows)/2; |
|
#else |
|
int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; |
|
int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; |
|
#endif //GTK_VERSION3 |
|
pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/ |
|
image_widget->scaled_image->cols ); |
|
pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/ |
|
image_widget->scaled_image->rows ); |
|
} |
|
else |
|
{ |
|
pt = cvPointFrom32f( pt32f ); |
|
} |
|
|
|
// if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) && |
|
// (unsigned)pt.y < (unsigned)(image_widget->original_image->height) ) |
|
{ |
|
flags |= BIT_MAP(state, GDK_SHIFT_MASK, CV_EVENT_FLAG_SHIFTKEY) | |
|
BIT_MAP(state, GDK_CONTROL_MASK, CV_EVENT_FLAG_CTRLKEY) | |
|
BIT_MAP(state, GDK_MOD1_MASK, CV_EVENT_FLAG_ALTKEY) | |
|
BIT_MAP(state, GDK_MOD2_MASK, CV_EVENT_FLAG_ALTKEY) | |
|
BIT_MAP(state, GDK_BUTTON1_MASK, CV_EVENT_FLAG_LBUTTON) | |
|
BIT_MAP(state, GDK_BUTTON2_MASK, CV_EVENT_FLAG_MBUTTON) | |
|
BIT_MAP(state, GDK_BUTTON3_MASK, CV_EVENT_FLAG_RBUTTON); |
|
window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param ); |
|
} |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
|
|
static gboolean icvAlarm( gpointer user_data ) |
|
{ |
|
*(int*)user_data = 1; |
|
return FALSE; |
|
} |
|
|
|
|
|
CV_IMPL int cvWaitKey( int delay ) |
|
{ |
|
#ifdef HAVE_GTHREAD |
|
if (thread_started && g_thread_self() != window_thread) |
|
{ |
|
gboolean expired = true; |
|
int my_last_key; |
|
|
|
g_mutex_lock(last_key_mutex); |
|
// wait for signal or timeout if delay > 0 |
|
if(delay>0){ |
|
GTimeVal timer; |
|
g_get_current_time(&timer); |
|
g_time_val_add(&timer, delay*1000); |
|
expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer); |
|
} |
|
else{ |
|
if (g_windows.empty()) |
|
{ |
|
CV_LOG_WARNING(NULL, "cv::waitKey() is called without timeout and missing active windows. Ignoring"); |
|
} |
|
else |
|
{ |
|
g_cond_wait(cond_have_key, last_key_mutex); |
|
expired=false; |
|
} |
|
} |
|
my_last_key = last_key; |
|
g_mutex_unlock(last_key_mutex); |
|
if(expired || g_windows.empty()){ |
|
return -1; |
|
} |
|
return my_last_key; |
|
} |
|
else |
|
#endif |
|
{ |
|
int expired = 0; |
|
guint timer = 0; |
|
if( delay > 0 ) |
|
timer = g_timeout_add( delay, icvAlarm, &expired ); |
|
last_key = -1; |
|
while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && (delay > 0 || !g_windows.empty())) |
|
; |
|
|
|
if( delay > 0 && !expired ) |
|
g_source_remove(timer); |
|
} |
|
return last_key; |
|
} |
|
|
|
|
|
#endif // HAVE_GTK |
|
#endif // _WIN32 |
|
|
|
/* End of file. */
|
|
|