The linux buildbots have started to fail compilation due to not finding the gtk headers. The quotes have been changed to angle brackets to indicate to the compiler that these are system includes.
1840 lines
49 KiB
C++
1840 lines
49 KiB
C++
/*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
|
|
#endif //GTK_MAJOR_VERSION >= 3
|
|
|
|
#ifdef HAVE_OPENGL
|
|
#include <gtk/gtkgl.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#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 ?
|
|
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 ?
|
|
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->cols : *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 (CvImageWidgetClass * klass)
|
|
{
|
|
#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 (CvImageWidget *image_widget)
|
|
{
|
|
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),
|
|
(GClassInitFunc) cvImageWidget_class_init,
|
|
sizeof(CvImageWidget),
|
|
(GInstanceInitFunc) cvImageWidget_init,
|
|
(GTypeFlags)NULL
|
|
);
|
|
}
|
|
|
|
return image_type;
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// End CvImageWidget
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
struct CvWindow;
|
|
|
|
typedef struct CvTrackbar
|
|
{
|
|
int signature;
|
|
GtkWidget* widget;
|
|
char* name;
|
|
CvTrackbar* next;
|
|
CvWindow* parent;
|
|
int* data;
|
|
int pos;
|
|
int maxval;
|
|
CvTrackbarCallback notify;
|
|
CvTrackbarCallback2 notify2;
|
|
void* userdata;
|
|
}
|
|
CvTrackbar;
|
|
|
|
|
|
typedef struct CvWindow
|
|
{
|
|
int signature;
|
|
GtkWidget* widget;
|
|
GtkWidget* frame;
|
|
GtkWidget* paned;
|
|
char* name;
|
|
CvWindow* prev;
|
|
CvWindow* next;
|
|
|
|
int last_key;
|
|
int flags;
|
|
int status;//0 normal, 1 fullscreen (YV)
|
|
|
|
CvMouseCallback on_mouse;
|
|
void* on_mouse_param;
|
|
|
|
struct
|
|
{
|
|
int pos;
|
|
int rows;
|
|
CvTrackbar* first;
|
|
}
|
|
toolbar;
|
|
|
|
#ifdef HAVE_OPENGL
|
|
bool useGl;
|
|
|
|
CvOpenGlDrawCallback glDrawCallback;
|
|
void* glDrawData;
|
|
#endif
|
|
}
|
|
CvWindow;
|
|
|
|
|
|
static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data );
|
|
static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data );
|
|
static void icvOnTrackbar( GtkWidget* widget, gpointer user_data );
|
|
static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data );
|
|
|
|
#ifdef HAVE_GTHREAD
|
|
int thread_started=0;
|
|
static gpointer icvWindowThreadLoop();
|
|
GMutex* last_key_mutex;
|
|
GCond* cond_have_key;
|
|
GMutex* window_mutex;
|
|
GThread* window_thread;
|
|
GtkWidget* cvTopLevelWidget = 0;
|
|
#endif
|
|
|
|
static int last_key = -1;
|
|
static CvWindow* hg_windows = 0;
|
|
|
|
CV_IMPL int cvInitSystem( int argc, char** argv )
|
|
{
|
|
static int wasInitialized = 0;
|
|
|
|
// check initialization status
|
|
if( !wasInitialized )
|
|
{
|
|
hg_windows = 0;
|
|
|
|
gtk_disable_setlocale();
|
|
gtk_init( &argc, &argv );
|
|
|
|
#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);
|
|
}
|
|
|
|
// this mutex protects the window resources
|
|
window_mutex = g_mutex_new();
|
|
|
|
// protects the 'last key pressed' variable
|
|
last_key_mutex = g_mutex_new();
|
|
|
|
// conditional that indicates a key has been pressed
|
|
cond_have_key = g_cond_new();
|
|
|
|
// this is the window update thread
|
|
window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
|
|
NULL, TRUE, NULL);
|
|
}
|
|
thread_started = window_thread!=NULL;
|
|
return thread_started;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_GTHREAD
|
|
gpointer icvWindowThreadLoop(){
|
|
while(1){
|
|
g_mutex_lock(window_mutex);
|
|
gtk_main_iteration_do(FALSE);
|
|
g_mutex_unlock(window_mutex);
|
|
|
|
// little sleep
|
|
g_usleep(500);
|
|
|
|
g_thread_yield();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define CV_LOCK_MUTEX() \
|
|
if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { }
|
|
|
|
#define CV_UNLOCK_MUTEX() \
|
|
if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { }
|
|
|
|
#else
|
|
#define CV_LOCK_MUTEX()
|
|
#define CV_UNLOCK_MUTEX()
|
|
#endif
|
|
|
|
static CvWindow* icvFindWindowByName( const char* name )
|
|
{
|
|
CvWindow* window = hg_windows;
|
|
while( window != 0 && strcmp(name, window->name) != 0 )
|
|
window = window->next;
|
|
|
|
return window;
|
|
}
|
|
|
|
static CvWindow* icvWindowByWidget( GtkWidget* widget )
|
|
{
|
|
CvWindow* window = hg_windows;
|
|
|
|
while( window != 0 && window->widget != widget &&
|
|
window->frame != widget && window->paned != widget )
|
|
window = window->next;
|
|
|
|
return window;
|
|
}
|
|
|
|
double cvGetModeWindow_GTK(const char* name)//YV
|
|
{
|
|
double result = -1;
|
|
|
|
CV_FUNCNAME( "cvGetModeWindow_GTK" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if (!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if (!window)
|
|
CV_ERROR( CV_StsNullPtr, "NULL window" );
|
|
|
|
CV_LOCK_MUTEX();
|
|
result = window->status;
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
return result;
|
|
}
|
|
|
|
|
|
void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
|
|
{
|
|
|
|
CV_FUNCNAME( "cvSetModeWindow_GTK" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if(!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if( !window )
|
|
CV_ERROR( CV_StsNullPtr, "NULL window" );
|
|
|
|
if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
|
|
EXIT;
|
|
|
|
//so easy to do fullscreen here, Linux rocks !
|
|
|
|
if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
|
|
{
|
|
CV_LOCK_MUTEX();
|
|
gtk_window_unfullscreen(GTK_WINDOW(window->frame));
|
|
window->status=CV_WINDOW_NORMAL;
|
|
CV_UNLOCK_MUTEX();
|
|
EXIT;
|
|
}
|
|
|
|
if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
|
|
{
|
|
CV_LOCK_MUTEX();
|
|
gtk_window_fullscreen(GTK_WINDOW(window->frame));
|
|
window->status=CV_WINDOW_FULLSCREEN;
|
|
CV_UNLOCK_MUTEX();
|
|
EXIT;
|
|
}
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
double cvGetPropWindowAutoSize_GTK(const char* name)
|
|
{
|
|
double result = -1;
|
|
|
|
CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if (!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if (!window)
|
|
EXIT; // keep silence here
|
|
|
|
result = window->flags & CV_WINDOW_AUTOSIZE;
|
|
|
|
__END__;
|
|
|
|
return result;
|
|
}
|
|
|
|
double cvGetRatioWindow_GTK(const char* name)
|
|
{
|
|
double result = -1;
|
|
|
|
CV_FUNCNAME( "cvGetRatioWindow_GTK" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if (!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if (!window)
|
|
EXIT; // keep silence here
|
|
|
|
#if defined (GTK_VERSION3)
|
|
result = static_cast<double>(
|
|
gtk_widget_get_allocated_width(window->widget)) / gtk_widget_get_allocated_height(window->widget);
|
|
#else
|
|
result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
|
|
#endif // GTK_VERSION3
|
|
__END__;
|
|
|
|
return result;
|
|
}
|
|
|
|
double cvGetOpenGlProp_GTK(const char* name)
|
|
{
|
|
double result = -1;
|
|
|
|
#ifdef HAVE_OPENGL
|
|
CV_FUNCNAME( "cvGetOpenGlProp_GTK" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if (!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if (!window)
|
|
EXIT; // keep silence here
|
|
|
|
result = window->useGl;
|
|
|
|
__END__;
|
|
#else
|
|
(void)name;
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// OpenGL support
|
|
|
|
#ifdef HAVE_OPENGL
|
|
|
|
namespace
|
|
{
|
|
void createGlContext(CvWindow* window)
|
|
{
|
|
GdkGLConfig* glconfig;
|
|
|
|
CV_FUNCNAME( "createGlContext" );
|
|
|
|
__BEGIN__;
|
|
|
|
// 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;
|
|
|
|
__END__;
|
|
}
|
|
|
|
void drawGl(CvWindow* window)
|
|
{
|
|
CV_FUNCNAME( "drawGl" );
|
|
|
|
__BEGIN__;
|
|
|
|
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);
|
|
|
|
__END__;
|
|
}
|
|
}
|
|
|
|
#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
|
|
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;
|
|
|
|
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);
|
|
|
|
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, 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);
|
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
|
|
}
|
|
|
|
cairo_paint(cr);
|
|
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);
|
|
g_object_unref(pixbuf);
|
|
cairo_destroy(cr);
|
|
return TRUE;
|
|
}
|
|
#endif //GTK_VERSION3
|
|
|
|
CV_IMPL int cvNamedWindow( const char* name, int flags )
|
|
{
|
|
int result = 0;
|
|
CV_FUNCNAME( "cvNamedWindow" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
int len;
|
|
|
|
cvInitSystem(1,(char**)&name);
|
|
if( !name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
// Check the name in the storage
|
|
if( icvFindWindowByName( name ) != 0 )
|
|
{
|
|
result = 1;
|
|
EXIT;
|
|
}
|
|
|
|
len = strlen(name);
|
|
CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
|
|
memset( window, 0, sizeof(*window));
|
|
window->name = (char*)(window + 1);
|
|
memcpy( window->name, name, len + 1 );
|
|
window->flags = flags;
|
|
window->signature = CV_WINDOW_MAGIC_VAL;
|
|
window->last_key = 0;
|
|
window->on_mouse = 0;
|
|
window->on_mouse_param = 0;
|
|
memset( &window->toolbar, 0, sizeof(window->toolbar));
|
|
window->next = hg_windows;
|
|
window->prev = 0;
|
|
window->status = CV_WINDOW_NORMAL;//YV
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
|
|
|
window->paned = gtk_vbox_new( FALSE, 0 );
|
|
window->widget = cvImageWidgetNew( flags );
|
|
gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 );
|
|
gtk_widget_show( window->widget );
|
|
gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
|
|
gtk_widget_show( window->paned );
|
|
|
|
#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->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
|
|
|
|
gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
|
|
|
|
gtk_widget_show( window->frame );
|
|
gtk_window_set_title( GTK_WINDOW(window->frame), name );
|
|
|
|
if( hg_windows )
|
|
hg_windows->prev = window;
|
|
hg_windows = window;
|
|
|
|
gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
|
|
|
|
|
|
// allow window to be resized
|
|
if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
|
|
GdkGeometry geometry;
|
|
geometry.min_width = 50;
|
|
geometry.min_height = 50;
|
|
gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ),
|
|
&geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE));
|
|
}
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
#ifdef HAVE_OPENGL
|
|
if (window->useGl)
|
|
cvSetOpenGlContext(name);
|
|
#endif
|
|
|
|
result = 1;
|
|
__END__;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
#ifdef HAVE_OPENGL
|
|
|
|
CV_IMPL void cvSetOpenGlContext(const char* name)
|
|
{
|
|
CvWindow* window;
|
|
GdkGLContext* glcontext;
|
|
GdkGLDrawable* gldrawable;
|
|
|
|
CV_FUNCNAME( "cvSetOpenGlContext" );
|
|
|
|
__BEGIN__;
|
|
|
|
if(!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
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" );
|
|
|
|
__END__;
|
|
}
|
|
|
|
CV_IMPL void cvUpdateWindow(const char* name)
|
|
{
|
|
CV_FUNCNAME( "cvUpdateWindow" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if (!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if (!window)
|
|
EXIT;
|
|
|
|
// window does not refresh without this
|
|
gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
|
|
|
|
__END__;
|
|
}
|
|
|
|
CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
|
|
{
|
|
CvWindow* window;
|
|
|
|
CV_FUNCNAME( "cvCreateOpenGLCallback" );
|
|
|
|
__BEGIN__;
|
|
|
|
if(!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if( !window )
|
|
EXIT;
|
|
|
|
if (!window->useGl)
|
|
CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
|
|
|
|
window->glDrawCallback = callback;
|
|
window->glDrawData = userdata;
|
|
|
|
__END__;
|
|
}
|
|
|
|
#endif // HAVE_OPENGL
|
|
|
|
|
|
|
|
|
|
static void icvDeleteWindow( CvWindow* window )
|
|
{
|
|
CvTrackbar* trackbar;
|
|
|
|
if( window->prev )
|
|
window->prev->next = window->next;
|
|
else
|
|
hg_windows = window->next;
|
|
|
|
if( window->next )
|
|
window->next->prev = window->prev;
|
|
|
|
window->prev = window->next = 0;
|
|
|
|
gtk_widget_destroy( window->frame );
|
|
|
|
for( trackbar = window->toolbar.first; trackbar != 0; )
|
|
{
|
|
CvTrackbar* next = trackbar->next;
|
|
cvFree( &trackbar );
|
|
trackbar = next;
|
|
}
|
|
|
|
cvFree( &window );
|
|
#ifdef HAVE_GTHREAD
|
|
// if last window, send key press signal
|
|
// to jump out of any waiting cvWaitKey's
|
|
if(hg_windows==0 && thread_started){
|
|
g_cond_broadcast(cond_have_key);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
CV_IMPL void cvDestroyWindow( const char* name )
|
|
{
|
|
CV_FUNCNAME( "cvDestroyWindow" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if(!name)
|
|
CV_ERROR( CV_StsNullPtr, "NULL name string" );
|
|
|
|
window = icvFindWindowByName( name );
|
|
if( !window )
|
|
EXIT;
|
|
|
|
// note that it is possible for the update thread to run this function
|
|
// if there is a call to cvShowImage in a mouse callback
|
|
// (this would produce a deadlock on window_mutex)
|
|
CV_LOCK_MUTEX();
|
|
|
|
icvDeleteWindow( window );
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
CV_IMPL void
|
|
cvDestroyAllWindows( void )
|
|
{
|
|
CV_LOCK_MUTEX();
|
|
|
|
while( hg_windows )
|
|
{
|
|
CvWindow* window = hg_windows;
|
|
icvDeleteWindow( window );
|
|
}
|
|
CV_UNLOCK_MUTEX();
|
|
}
|
|
|
|
// CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){
|
|
// CvSize window_size;
|
|
// GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame );
|
|
// gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window),
|
|
// &window_size.width, &window_size.height );
|
|
|
|
// window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width;
|
|
// window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height;
|
|
|
|
// return window_size;
|
|
// }
|
|
|
|
CV_IMPL void
|
|
cvShowImage( const char* name, const CvArr* arr )
|
|
{
|
|
CV_FUNCNAME( "cvShowImage" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if( !name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL name" );
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
window = icvFindWindowByName(name);
|
|
if(!window)
|
|
{
|
|
cvNamedWindow(name, 1);
|
|
window = icvFindWindowByName(name);
|
|
}
|
|
|
|
if( window && arr )
|
|
{
|
|
#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_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
}
|
|
|
|
CV_IMPL void cvResizeWindow(const char* name, int width, int height )
|
|
{
|
|
CV_FUNCNAME( "cvResizeWindow" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
CvImageWidget * image_widget;
|
|
|
|
if( !name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL name" );
|
|
|
|
window = icvFindWindowByName(name);
|
|
if(!window)
|
|
EXIT;
|
|
|
|
image_widget = CV_IMAGE_WIDGET( window->widget );
|
|
//if(image_widget->flags & CV_WINDOW_AUTOSIZE)
|
|
//EXIT;
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 );
|
|
gtk_window_resize( GTK_WINDOW(window->frame), width, height );
|
|
|
|
// disable initial resize since presumably user wants to keep
|
|
// this window size
|
|
image_widget->flags &= ~CV_WINDOW_NO_IMAGE;
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
CV_IMPL void cvMoveWindow( const char* name, int x, int y )
|
|
{
|
|
CV_FUNCNAME( "cvMoveWindow" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if( !name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL name" );
|
|
|
|
window = icvFindWindowByName(name);
|
|
if(!window)
|
|
EXIT;
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
gtk_window_move( GTK_WINDOW(window->frame), x, y );
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
static CvTrackbar*
|
|
icvFindTrackbarByName( const CvWindow* window, const char* name )
|
|
{
|
|
CvTrackbar* trackbar = window->toolbar.first;
|
|
|
|
for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
|
|
;
|
|
|
|
return trackbar;
|
|
}
|
|
|
|
static int
|
|
icvCreateTrackbar( const char* trackbar_name, const char* window_name,
|
|
int* val, int count, CvTrackbarCallback on_notify,
|
|
CvTrackbarCallback2 on_notify2, void* userdata )
|
|
{
|
|
int result = 0;
|
|
|
|
CV_FUNCNAME( "icvCreateTrackbar" );
|
|
|
|
__BEGIN__;
|
|
|
|
/*char slider_name[32];*/
|
|
CvWindow* window = 0;
|
|
CvTrackbar* trackbar = 0;
|
|
|
|
if( !window_name || !trackbar_name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
|
|
|
|
if( count <= 0 )
|
|
CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
|
|
|
|
window = icvFindWindowByName(window_name);
|
|
if( !window )
|
|
EXIT;
|
|
|
|
trackbar = icvFindTrackbarByName(window,trackbar_name);
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
if( !trackbar )
|
|
{
|
|
int len = strlen(trackbar_name);
|
|
trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
|
|
memset( trackbar, 0, sizeof(*trackbar));
|
|
trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
|
|
trackbar->name = (char*)(trackbar+1);
|
|
memcpy( trackbar->name, trackbar_name, len + 1 );
|
|
trackbar->parent = window;
|
|
trackbar->next = window->toolbar.first;
|
|
window->toolbar.first = trackbar;
|
|
|
|
GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 );
|
|
GtkWidget* hscale_label = gtk_label_new( trackbar_name );
|
|
GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 );
|
|
gtk_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) );
|
|
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
result = 1;
|
|
|
|
__END__;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
CV_IMPL int
|
|
cvCreateTrackbar( const char* trackbar_name, const char* window_name,
|
|
int* val, int count, CvTrackbarCallback on_notify )
|
|
{
|
|
return icvCreateTrackbar(trackbar_name, window_name, val, count,
|
|
on_notify, 0, 0);
|
|
}
|
|
|
|
|
|
CV_IMPL int
|
|
cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
|
|
int* val, int count, CvTrackbarCallback2 on_notify2,
|
|
void* userdata )
|
|
{
|
|
return icvCreateTrackbar(trackbar_name, window_name, val, count,
|
|
0, on_notify2, userdata);
|
|
}
|
|
|
|
|
|
CV_IMPL void
|
|
cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
|
|
{
|
|
CV_FUNCNAME( "cvSetMouseCallback" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window = 0;
|
|
|
|
if( !window_name )
|
|
CV_ERROR( CV_StsNullPtr, "NULL window name" );
|
|
|
|
window = icvFindWindowByName(window_name);
|
|
if( !window )
|
|
EXIT;
|
|
|
|
window->on_mouse = on_mouse;
|
|
window->on_mouse_param = param;
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
|
|
{
|
|
int pos = -1;
|
|
|
|
CV_FUNCNAME( "cvGetTrackbarPos" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
CvTrackbar* trackbar = 0;
|
|
|
|
if( trackbar_name == 0 || window_name == 0 )
|
|
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
|
|
|
|
window = icvFindWindowByName( window_name );
|
|
if( window )
|
|
trackbar = icvFindTrackbarByName( window, trackbar_name );
|
|
|
|
if( trackbar )
|
|
pos = trackbar->pos;
|
|
|
|
__END__;
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
|
|
{
|
|
CV_FUNCNAME( "cvSetTrackbarPos" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
CvTrackbar* trackbar = 0;
|
|
|
|
if( trackbar_name == 0 || window_name == 0 )
|
|
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
|
|
|
|
window = icvFindWindowByName( window_name );
|
|
if( window )
|
|
trackbar = icvFindTrackbarByName( window, trackbar_name );
|
|
|
|
if( trackbar )
|
|
{
|
|
if( pos < 0 )
|
|
pos = 0;
|
|
|
|
if( pos > trackbar->maxval )
|
|
pos = trackbar->maxval;
|
|
}
|
|
|
|
CV_LOCK_MUTEX();
|
|
|
|
gtk_range_set_value( GTK_RANGE(trackbar->widget), pos );
|
|
|
|
CV_UNLOCK_MUTEX();
|
|
|
|
__END__;
|
|
}
|
|
|
|
|
|
CV_IMPL void* cvGetWindowHandle( const char* window_name )
|
|
{
|
|
void* widget = 0;
|
|
|
|
CV_FUNCNAME( "cvGetWindowHandle" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if( window_name == 0 )
|
|
CV_ERROR( CV_StsNullPtr, "NULL window name" );
|
|
|
|
window = icvFindWindowByName( window_name );
|
|
if( window )
|
|
widget = (void*)window->widget;
|
|
|
|
__END__;
|
|
|
|
return widget;
|
|
}
|
|
|
|
|
|
CV_IMPL const char* cvGetWindowName( void* window_handle )
|
|
{
|
|
const char* window_name = "";
|
|
|
|
CV_FUNCNAME( "cvGetWindowName" );
|
|
|
|
__BEGIN__;
|
|
|
|
CvWindow* window;
|
|
|
|
if( window_handle == 0 )
|
|
CV_ERROR( CV_StsNullPtr, "NULL window" );
|
|
|
|
window = icvWindowByWidget( (GtkWidget*)window_handle );
|
|
if( window )
|
|
window_name = window->name;
|
|
|
|
__END__;
|
|
|
|
return window_name;
|
|
}
|
|
|
|
#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
|
|
#endif //GTK_VERSION3
|
|
|
|
static gboolean icvOnKeyPress( GtkWidget * /*widget*/,
|
|
GdkEventKey* event, gpointer /*user_data*/ )
|
|
{
|
|
int code = 0;
|
|
|
|
switch( event->keyval )
|
|
{
|
|
case GDK_Escape:
|
|
code = 27;
|
|
break;
|
|
case GDK_Return:
|
|
case GDK_Linefeed:
|
|
code = '\n';
|
|
break;
|
|
case GDK_Tab:
|
|
code = '\t';
|
|
break;
|
|
default:
|
|
code = event->keyval;
|
|
}
|
|
|
|
code |= event->state << 16;
|
|
|
|
#ifdef HAVE_GTHREAD
|
|
if(thread_started) g_mutex_lock(last_key_mutex);
|
|
#endif
|
|
|
|
last_key = code;
|
|
|
|
#ifdef HAVE_GTHREAD
|
|
if(thread_started){
|
|
// signal any waiting threads
|
|
g_cond_broadcast(cond_have_key);
|
|
g_mutex_unlock(last_key_mutex);
|
|
}
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void icvOnTrackbar( GtkWidget* widget, gpointer user_data )
|
|
{
|
|
int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget)));
|
|
CvTrackbar* trackbar = (CvTrackbar*)user_data;
|
|
|
|
if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
|
|
trackbar->widget == widget )
|
|
{
|
|
trackbar->pos = pos;
|
|
if( trackbar->data )
|
|
*trackbar->data = pos;
|
|
if( trackbar->notify2 )
|
|
trackbar->notify2(pos, trackbar->userdata);
|
|
else if( trackbar->notify )
|
|
trackbar->notify(pos);
|
|
}
|
|
}
|
|
|
|
static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data )
|
|
{
|
|
CvWindow* window = (CvWindow*)user_data;
|
|
if( window->signature == CV_WINDOW_MAGIC_VAL &&
|
|
window->frame == widget )
|
|
{
|
|
icvDeleteWindow(window);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data )
|
|
{
|
|
// TODO move this logic to CvImageWidget
|
|
CvWindow* window = (CvWindow*)user_data;
|
|
CvPoint2D32f pt32f(-1., -1.);
|
|
CvPoint pt(-1,-1);
|
|
int cv_event = -1, state = 0;
|
|
CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
|
|
|
|
if( window->signature != CV_WINDOW_MAGIC_VAL ||
|
|
window->widget != widget || !window->widget ||
|
|
!window->on_mouse /*|| !image_widget->original_image*/)
|
|
return FALSE;
|
|
|
|
if( event->type == GDK_MOTION_NOTIFY )
|
|
{
|
|
GdkEventMotion* event_motion = (GdkEventMotion*)event;
|
|
|
|
cv_event = CV_EVENT_MOUSEMOVE;
|
|
pt32f.x = cvRound(event_motion->x);
|
|
pt32f.y = cvRound(event_motion->y);
|
|
state = event_motion->state;
|
|
}
|
|
else if( event->type == GDK_BUTTON_PRESS ||
|
|
event->type == GDK_BUTTON_RELEASE ||
|
|
event->type == GDK_2BUTTON_PRESS )
|
|
{
|
|
GdkEventButton* event_button = (GdkEventButton*)event;
|
|
pt32f.x = cvRound(event_button->x);
|
|
pt32f.y = cvRound(event_button->y);
|
|
|
|
|
|
if( event_button->type == GDK_BUTTON_PRESS )
|
|
{
|
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN :
|
|
event_button->button == 2 ? CV_EVENT_MBUTTONDOWN :
|
|
event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0;
|
|
}
|
|
else if( event_button->type == GDK_BUTTON_RELEASE )
|
|
{
|
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP :
|
|
event_button->button == 2 ? CV_EVENT_MBUTTONUP :
|
|
event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0;
|
|
}
|
|
else if( event_button->type == GDK_2BUTTON_PRESS )
|
|
{
|
|
cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK :
|
|
event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK :
|
|
event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0;
|
|
}
|
|
state = event_button->state;
|
|
}
|
|
|
|
if( cv_event >= 0 ){
|
|
// scale point if image is scaled
|
|
if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
|
|
image_widget->original_image &&
|
|
image_widget->scaled_image ){
|
|
// image origin is not necessarily at (0,0)
|
|
#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) )
|
|
{
|
|
int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
|
|
(state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
|
|
(state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
|
|
(state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
|
|
(state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
|
|
(state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
|
|
window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static gboolean icvAlarm( gpointer user_data )
|
|
{
|
|
*(int*)user_data = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
CV_IMPL int cvWaitKey( int delay )
|
|
{
|
|
#ifdef HAVE_GTHREAD
|
|
if(thread_started && g_thread_self()!=window_thread){
|
|
gboolean expired;
|
|
int my_last_key;
|
|
|
|
// wait for signal or timeout if delay > 0
|
|
if(delay>0){
|
|
GTimeVal timer;
|
|
g_get_current_time(&timer);
|
|
g_time_val_add(&timer, delay*1000);
|
|
expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer);
|
|
}
|
|
else{
|
|
g_cond_wait(cond_have_key, last_key_mutex);
|
|
expired=false;
|
|
}
|
|
my_last_key = last_key;
|
|
g_mutex_unlock(last_key_mutex);
|
|
if(expired || hg_windows==0){
|
|
return -1;
|
|
}
|
|
return my_last_key;
|
|
}
|
|
else{
|
|
#endif
|
|
int expired = 0;
|
|
guint timer = 0;
|
|
if( delay > 0 )
|
|
timer = g_timeout_add( delay, icvAlarm, &expired );
|
|
last_key = -1;
|
|
while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 )
|
|
;
|
|
|
|
if( delay > 0 && !expired )
|
|
g_source_remove(timer);
|
|
#ifdef HAVE_GTHREAD
|
|
}
|
|
#endif
|
|
return last_key;
|
|
}
|
|
|
|
|
|
#endif // HAVE_GTK
|
|
#endif // WIN32
|
|
|
|
/* End of file. */
|