C LIBCHAMPLAIN SegFault? - c

I had a programm with C and libchamplain which showed a map. worked fine. Now i wanted to integrate it into an gtk application. But at running, i get a segfault:
#include <stdio.h>
#include <gtk/gtk.h>
#include <champlain/champlain.h>
#include <champlain-gtk/champlain-gtk.h>
#include <clutter-gtk/clutter-gtk.h>
#include <math.h>
#include "GPS_stub.h"
#define MARKER_SIZE 10
#define MAX_SIZ 4096
static gboolean draw_center(ClutterCanvas *canvas, cairo_t *cr, int width, int height){
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_arc(cr, MARKER_SIZE / 2.0, MARKER_SIZE / 2.0, MARKER_SIZE / 2.0, 0, 2 * M_PI);
cairo_close_path(cr);
cairo_set_source_rgba(cr, 0.1, 0.1, 0.9, 1.0);
cairo_fill(cr);
return TRUE;
}
static ClutterActor *create_marker(void){
ClutterActor *marker;
ClutterActor *bg;
ClutterContent *canvas;
ClutterTransition *transition;
marker = champlain_custom_marker_new();
canvas = clutter_canvas_new();
clutter_canvas_set_size(CLUTTER_CANVAS(canvas), MARKER_SIZE, MARKER_SIZE);
g_signal_connect(canvas, "draw", G_CALLBACK(draw_center), NULL);
bg = clutter_actor_new();
clutter_actor_set_size(bg, MARKER_SIZE, MARKER_SIZE);
clutter_actor_set_content(bg, canvas);
clutter_content_invalidate(canvas);
g_object_unref(canvas);
clutter_actor_add_child(marker, bg);
clutter_actor_set_pivot_point(bg, 0.5, 0.5);
clutter_actor_set_position(bg, -MARKER_SIZE, -MARKER_SIZE);
transition = clutter_property_transition_new("opacity");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_UINT, 255);
clutter_transition_set_to(transition, G_TYPE_UINT, 0);
clutter_actor_add_transition(bg, "animate-opacity", transition);
transition = clutter_property_transition_new("scale-x");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_FLOAT, 0.5);
clutter_transition_set_to(transition, G_TYPE_FLOAT, 1.0);
clutter_actor_add_transition(bg, "animate-scale-x", transition);
transition = clutter_property_transition_new("scale-y");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_FLOAT, 0.5);
clutter_transition_set_to(transition, G_TYPE_FLOAT, 1.0);
clutter_actor_add_transition(bg, "animate-scale-y", transition);
return marker;
}
static gboolean gps_callback(ChamplainMarker *marker[MAX_SIZ]){
return TRUE;
}
typedef struct{
double lat;
double lng;
} GpsCallbackData;
static void load_map(GpsCallbackData *data){
ClutterActor *actor, *stage;
ChamplainMarkerLayer *layer;
ClutterActor *marker[MAX_SIZ];
stage = clutter_stage_new();
clutter_actor_set_size(stage, 800, 600);
g_signal_connect(stage, "destroy", G_CALLBACK(clutter_main_quit), NULL);
actor = champlain_view_new();
clutter_actor_set_size(CLUTTER_ACTOR(actor), 800, 600);
clutter_actor_add_child(stage, actor);
layer = champlain_marker_layer_new_full(CHAMPLAIN_SELECTION_SINGLE);
clutter_actor_show(CLUTTER_ACTOR(layer));
champlain_view_add_layer(CHAMPLAIN_VIEW(actor), CHAMPLAIN_LAYER(layer));
for(int i = 0; i < MAX_SIZ/40; i++){
marker[i] = create_marker();
champlain_marker_layer_add_marker(layer, CHAMPLAIN_MARKER(marker[i]));
champlain_location_set_location(CHAMPLAIN_LOCATION(marker[i]), data->lat+i/10, data->lng+i/10);
}
g_object_set(G_OBJECT(actor), "zoom-level", 2, "kinetic-mode", TRUE, NULL);
champlain_view_center_on(CHAMPLAIN_VIEW(actor), 40, 0);
g_timeout_add(1000, (GSourceFunc) gps_callback, CHAMPLAIN_MARKER(marker));
clutter_actor_show(stage);
clutter_main();
}
int main(int argc, char *argv[]){
GtkWidget *window, *button;
GpsCallbackData *gps;
double lat, lng;
gtk_clutter_init(&argc, &argv);
hs_init(&argc, &argv);
getGPS("166.82.21.200", &lat, &lng);
printf("GPS: %f %f\n", lat, lng);
gps->lat = lat;
gps->lng = lng;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
button = gtk_button_new_with_label("Load Map");
g_signal_connect(button, "clicked", G_CALLBACK(load_map), &gps);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show(window);
gtk_main();
hs_exit();
return 0;
}
like you can see in main , it prints out coordinates. This works fine. But then after the printing i'm getting an segfault.
Why?

I have a same problem on ARM Linux from here.
stage = clutter_stage_new();
clutter_actor_set_size(stage, 800, 600);
When I removed or blocked "clutter_actor_set", there's no seg fault error.
actor is O.K, but stage is matter.
But on X86 Ubuntu desktop, it's O.K.

Related

How to draw in a GTK3 area with scroll bars

I am building a nested GTK application:
There is GtkNotebook - GtkGrid - GtkGrid - GtkFrame - GtkDrawingArea.
In GtkDrawingArea (I fix the size through a size request) I create drawings and I have built the possibility to zoom via the scroll wheel.
Logically, when I 'zoom in' the surface becomes bigger and scroll bars are needed to view the whole drawing.
How can I get these? I tried GtkLayout and GtkSrolledWindow in different combinations but they didn't work. I haven't found any useful example on the Internet.
What's the way to get a scrollable drawing area?
Where should I start to dig in? Any hints are very appreciated!
Thank you.
BTW: I am using Debian, GTK3, C and Cairo
MCVE: I created this example. It draws a rectangle and you can zoom it by using your scroll wheel. This happens within a 300x300 frame. I'd like to have this frame with scrollbars. Any ideas how to do this?
This code can be compiled by using
gcc `pkg-config --cflags gtk+-3.0` -lm -o cf cf.c `pkg-config --libs gtk+-3.0`
cf.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>
#define ZOOMING_STEP 1.2
typedef struct m_data
{
double scaling_factor;
cairo_surface_t *circle_surface_p, *final_surface_p;
GtkWidget *window_p;
} m_data_struct;
static void activate(GtkApplication *, gpointer);
static gboolean zoom_it(GtkWidget *, GdkEvent *, gpointer);
static gboolean configure_it(GtkWidget *, GdkEventConfigure *, gpointer);
static gboolean draw_it(GtkWidget *, cairo_t *, gpointer);
int main(int argc, char **argv)
{
GtkApplication *app_p;
m_data_struct my_data;
int status;
my_data.scaling_factor = 1.0/11.0;
my_data.final_surface_p = NULL;
app_p = gtk_application_new("calc.foil", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app_p, "activate", G_CALLBACK(activate), &my_data);
status = g_application_run(G_APPLICATION(app_p), 0, NULL);
g_object_unref(app_p);
}
static void activate(GtkApplication *app_p, gpointer g_data_p)
{
GtkWidget *frame_p, *notebook_p, *grid0_p, *grid1_p, *drawing_area_p;
m_data_struct *my_data_p;
cairo_t *cr_p;
my_data_p = (m_data_struct *)g_data_p;
my_data_p->window_p = gtk_application_window_new(app_p);
gtk_window_set_title(GTK_WINDOW(my_data_p->window_p), "Fot Calculation");
gtk_container_set_border_width(GTK_CONTAINER(my_data_p->window_p), 8);
notebook_p = gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(my_data_p->window_p), notebook_p);
grid0_p = gtk_grid_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_p), grid0_p,
gtk_label_new("First Tab"));
grid1_p = gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid0_p), grid1_p, 2, 2, 2, 50);
frame_p = gtk_frame_new("Rectangle");
drawing_area_p = gtk_drawing_area_new();
gtk_widget_set_size_request(frame_p, 300, 300);
g_signal_connect(drawing_area_p, "configure-event",
G_CALLBACK(configure_it), g_data_p);
g_signal_connect(drawing_area_p, "draw", G_CALLBACK(draw_it), g_data_p);
g_signal_connect(drawing_area_p, "scroll-event", G_CALLBACK(zoom_it),
g_data_p);
gtk_widget_set_events(drawing_area_p,
gtk_widget_get_events(drawing_area_p)
| GDK_SCROLL_MASK);
gtk_container_add(GTK_CONTAINER(frame_p), drawing_area_p);
gtk_grid_attach(GTK_GRID(grid1_p), frame_p, 1, 0, 1, 2);
my_data_p->circle_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 3000, 3000);
cr_p = cairo_create(my_data_p->circle_surface_p);
cairo_set_line_width(cr_p, 10);
cairo_rectangle(cr_p, 100, 100, 2900, 2900);
cairo_set_source_rgb(cr_p, 0, 0, 0);
cairo_stroke(cr_p);
gtk_widget_show_all(my_data_p->window_p);
}
static gboolean zoom_it(GtkWidget *widget_p,
GdkEvent *event_p,
gpointer g_data_p)
{
if (((GdkEventScroll *)event_p)->direction == GDK_SCROLL_UP)
{
((m_data_struct *)g_data_p)->scaling_factor *= ZOOMING_STEP;
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
if (((GdkEventScroll *)event_p)->direction == GDK_SCROLL_DOWN)
{
((m_data_struct *)g_data_p)->scaling_factor /= ZOOMING_STEP;
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
return TRUE;
}
static gboolean configure_it(GtkWidget *widget_p,
GdkEventConfigure *event_p,
gpointer g_data_p)
{
cairo_t *cr_p;
m_data_struct * my_data_p;
my_data_p = (m_data_struct *)g_data_p;
if (my_data_p->final_surface_p)
cairo_surface_destroy(my_data_p->final_surface_p);
my_data_p->final_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300);
cr_p = cairo_create(my_data_p->final_surface_p);
cairo_scale(cr_p, my_data_p->scaling_factor, my_data_p->scaling_factor);
cairo_set_source_surface(cr_p, my_data_p->circle_surface_p, 0, 0);
cairo_paint(cr_p);
cairo_destroy(cr_p);
return TRUE;
}
static gboolean draw_it(GtkWidget *widget_p,
cairo_t *cr_p,
gpointer g_data_p)
{
cairo_set_source_surface(cr_p, ((m_data_struct *)g_data_p)->final_surface_p,
0, 0);
cairo_paint(cr_p);
return FALSE;
}
To produce a scrollable GTK drawing area (GtkDrawingArea) a scrolled window can be taken (GtkScrolledWindow). The drawing area is a child of the scrolled window (gtk_container_add).
However, to scroll the drawing area I need to specify its size every time it changes it (gtk_widget_set_size_request). And, of course, scrolling only makes sense if its size is bigger than the size of the scrolled window.
Finally I wanted to use the scroll wheel to zoom into my Cairo drawing. This only works well if the point under the mouse is fixed. So I needed to adjust the scrolled window (GtkAdjustment) not to have the drawing moved under the mouse. Unless when zooming out to the very low levels.
However I couldn't find out where these adjustments are set when the drawing areas are changed so I had to do it manually when zooming in.
I changed the example in a way that it's working now. The code is complete to run:
cf.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>
#define ZOOMING_STEP 1.2
#define SCALING_FACTOR_INIT 1.0/10.0
typedef struct m_data
{
double scaling_factor;
cairo_surface_t *rectangle_surface_p, *final_surface_p;
GtkWidget *window_p, *drawing_area_p;
GtkAdjustment *hadjust_p, *vadjust_p;
} m_data_struct;
static void activate(GtkApplication *, gpointer);
static gboolean zoom_it(GtkWidget *, GdkEvent *, gpointer);
static gboolean configure_it(GtkWidget *, GdkEventConfigure *, gpointer);
static gboolean draw_it(GtkWidget *, cairo_t *, gpointer);
int main(int argc, char **argv)
{
GtkApplication *app_p;
m_data_struct my_data;
int status;
my_data.scaling_factor = SCALING_FACTOR_INIT;
my_data.final_surface_p = NULL;
app_p = gtk_application_new("calc.foil", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app_p, "activate", G_CALLBACK(activate), &my_data);
status = g_application_run(G_APPLICATION(app_p), 0, NULL);
g_object_unref(app_p);
}
static void activate(GtkApplication *app_p, gpointer g_data_p)
{
GtkWidget *frame_p, *notebook_p, *grid0_p, *grid1_p, *drawing_area_p;
GtkWidget *scrolled_window_p, *frame0_p;
m_data_struct *my_data_p;
cairo_t *cr_p;
my_data_p = (m_data_struct *)g_data_p;
my_data_p->window_p = gtk_application_window_new(app_p);
gtk_window_set_title(GTK_WINDOW(my_data_p->window_p), "Fot Calculation");
gtk_container_set_border_width(GTK_CONTAINER(my_data_p->window_p), 8);
notebook_p = gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(my_data_p->window_p), notebook_p);
grid0_p = gtk_grid_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_p), grid0_p,
gtk_label_new("First Tab"));
grid1_p = gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid0_p), grid1_p, 2, 2, 2, 50);
frame_p = gtk_frame_new("Rectangle");
gtk_frame_set_shadow_type(GTK_FRAME(frame_p), GTK_SHADOW_NONE);
frame0_p = gtk_frame_new(NULL);
scrolled_window_p = gtk_scrolled_window_new(NULL, NULL);
my_data_p->hadjust_p
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW
(scrolled_window_p));
my_data_p->vadjust_p
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW
(scrolled_window_p));
drawing_area_p = gtk_drawing_area_new();
gtk_widget_set_size_request(scrolled_window_p, 300, 300);
g_signal_connect(drawing_area_p, "configure-event",
G_CALLBACK(configure_it), g_data_p);
g_signal_connect(drawing_area_p, "draw", G_CALLBACK(draw_it), g_data_p);
g_signal_connect(drawing_area_p, "scroll-event", G_CALLBACK(zoom_it),
g_data_p);
gtk_widget_set_events(drawing_area_p,
gtk_widget_get_events(drawing_area_p)
| GDK_SCROLL_MASK);
my_data_p->drawing_area_p = drawing_area_p;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_p),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrolled_window_p), drawing_area_p);
gtk_container_add(GTK_CONTAINER(frame_p), frame0_p);
gtk_container_add(GTK_CONTAINER(frame0_p), scrolled_window_p);
gtk_grid_attach(GTK_GRID(grid1_p), frame_p, 1, 0, 1, 2);
my_data_p->rectangle_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 3000, 3000);
cr_p = cairo_create(my_data_p->rectangle_surface_p);
cairo_set_line_width(cr_p, 50);
cairo_rectangle(cr_p, 100, 100, 1375, 1375);
cairo_rectangle(cr_p, 1525, 1525, 1375, 1375);
cairo_set_source_rgb(cr_p, 0, 0, 0);
cairo_stroke(cr_p);
gtk_widget_show_all(my_data_p->window_p);
}
static gboolean zoom_it(GtkWidget *widget_p,
GdkEvent *event_p,
gpointer g_data_p)
{
m_data_struct *my_data_p;
GdkEventScroll *this_event_p;
gdouble new_x, new_y;
int do_zoom = 0;
my_data_p = (m_data_struct *)g_data_p;
this_event_p = (GdkEventScroll *)event_p;
if (this_event_p->direction == GDK_SCROLL_UP)
{
my_data_p->scaling_factor *= ZOOMING_STEP;
gtk_adjustment_set_upper(my_data_p->hadjust_p,
gtk_adjustment_get_upper(my_data_p->hadjust_p)
* ZOOMING_STEP
+ 1); /* we need to calc the new upper
to set value, +1 for
inaccuracy */
gtk_adjustment_set_upper(my_data_p->vadjust_p,
gtk_adjustment_get_upper(my_data_p->vadjust_p)
* ZOOMING_STEP
+ 1);
new_x = this_event_p->x * ZOOMING_STEP;
new_y = this_event_p->y * ZOOMING_STEP;
do_zoom = 1;
}
if (this_event_p->direction == GDK_SCROLL_DOWN)
{
double sf;
sf = my_data_p->scaling_factor / ZOOMING_STEP;
if (sf >= SCALING_FACTOR_INIT / (1 + (ZOOMING_STEP - 1) / 2))
/* zoom out max till level 0 but
preventing inability not to zoom
to level 0 due to inaccurancy */
{
my_data_p->scaling_factor = sf;
new_x = this_event_p->x / ZOOMING_STEP;
new_y = this_event_p->y / ZOOMING_STEP;
do_zoom = 1;
}
}
if (do_zoom)
{
gtk_adjustment_set_value
(my_data_p->hadjust_p,
new_x
+ gtk_adjustment_get_value(my_data_p->hadjust_p)
- this_event_p->x);
gtk_adjustment_set_value
(my_data_p->vadjust_p,
new_y
+ gtk_adjustment_get_value(my_data_p->vadjust_p)
- this_event_p->y);
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
return TRUE;
}
static gboolean configure_it(GtkWidget *widget_p,
GdkEventConfigure *event_p,
gpointer g_data_p)
{
cairo_t *cr_p;
m_data_struct *my_data_p;
my_data_p = (m_data_struct *)g_data_p;
if (my_data_p->final_surface_p)
cairo_surface_destroy(my_data_p->final_surface_p);
my_data_p->final_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
3000 * my_data_p->scaling_factor,
3000 * my_data_p->scaling_factor);
gtk_widget_set_size_request(my_data_p->drawing_area_p,
3000 * my_data_p->scaling_factor,
3000 * my_data_p->scaling_factor);
cr_p = cairo_create(my_data_p->final_surface_p);
cairo_scale(cr_p, my_data_p->scaling_factor, my_data_p->scaling_factor);
cairo_set_source_surface(cr_p, my_data_p->rectangle_surface_p, 0, 0);
cairo_paint(cr_p);
cairo_destroy(cr_p);
return TRUE;
}
static gboolean draw_it(GtkWidget *widget_p,
cairo_t *cr_p,
gpointer g_data_p)
{
cairo_set_source_surface(cr_p, ((m_data_struct *)g_data_p)->final_surface_p,
0, 0);
cairo_paint(cr_p);
return FALSE;
}

Is this simplification of GTK+ code correct?

I found the following GTK+3 code in Zetcode. It creates an animation using the cairo library while displaying an image:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
static void do_drawing(cairo_t *);
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
I achieve exatly the same result if I remove the do_drawing() function and move its code to the on_draw_event(), like:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
return FALSE;
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
So... I wonder... Am I missing something here (loss of generality)?
Or was the call to do_drawing() in function on_draw_event() of the original code redundant?
Thanks
Yes. It's correct on compiler's side.
But it's a good practice for functions to solve exactly one task. do_drawing is busy with drawing lines and pixels, on_draw_event is busy with processing events. Probably in this code snippet there is no real reason to make a separate function, but usually on_draw_event would be much more complicated.

Create a Rounded image in gtk

How can I make an image round?
I tried setting border-radius to gtk image. But it does not work. Here is my code.
GdkPixbuf *pixbuf;
pixbuf=gdk_pixbuf_new_from_file_at_size ("sample.jpg", 48, 48, NULL);
GtkWidget *image = GTK_WIDGET(gtk_builder_get_object(builder,"image"));;
gtk_image_set_from_pixbuf(GTK_IMAGE(image),pixbuf);
g_object_unref (pixbuf);
I want to round the image widget. Is there any option in glade to round the image? I don't find any.
Thanks.
As pointed out by #iharob in comments, you need a cairo surface .
Change the radius (in this example 40) to the desired size:
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
static void do_drawing(cairo_t *, GtkWidget *);
struct {
cairo_surface_t *image;
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr, widget);
return FALSE;
}
static void do_drawing(cairo_t *cr, GtkWidget *widget)
{
GtkWidget *win = gtk_widget_get_toplevel(widget);
gint width, height;
gtk_window_get_size(GTK_WINDOW(win), &width, &height);
cairo_set_source_surface(cr, glob.image, 1, 1);
cairo_arc(cr, /*x*/ 128, /* y */ 128, /* radius */ 40, 0, 2*M_PI);
cairo_clip(cr);
cairo_paint(cr);
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
gint width, height;
glob.image = cairo_image_surface_create_from_png("image.png");
width = cairo_image_surface_get_width(glob.image);
height = cairo_image_surface_get_height(glob.image);
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), width+2, height+2);
gtk_window_set_title(GTK_WINDOW(window), "Round image");
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
return 0;
}
// compila con valac --pkg cairo nombre_archivo.gs
uses Cairo
init
// crea una superficie (una imagen de 256x256) y un contexto
surface: Cairo.ImageSurface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 256, 256)
context: Cairo.Context = new Cairo.Context (surface)
// arco
context.arc (128.0, 128.0, 76.8, 0, 2*Math.PI)
context.clip () // recorta el arco
context.new_path () // después de clip, la ruta se borró
// imagen de origen (ruta y formato)
image_path:string = GLib.Path.build_filename (GLib.Path.get_dirname (args[0]) , "paisaje.png")
image: Cairo.ImageSurface = new Cairo.ImageSurface.from_png (image_path)
// escala
w:int = image.get_width ()
h:int= image.get_height ()
context.scale (256.0/w, 256.0/h)
context.set_source_surface (image, 0, 0)
context.paint ()
// guarda la nueva imagen
surface.write_to_png ("paisaje_arco.png")
More examples of Genie + Gtk + Cairo in http://genie.webierta.skn1.com

gtk_adjustment_get_value segmentation fault

I'm trying to code some simple stuff in C, with GTK+ and Cairo, but I'm having some troubles using the gtk_adjustment_get_value function.
This is my code:
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
#include <gtk/gtkhscale.h>
#include <math.h>
typedef struct
{
GtkAdjustment *adj[2]; //Adjustments para as escalas
GtkWidget *scale[2]; //Escalas
} ProgInfo;
gboolean
on_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
cairo_t *cr;
double pos1x, pos1y;
static gdouble pos2x = 450., pos2y = 290.; //Coordenadas Espelho
static gdouble pos3x = 450., pos3y = 250.;
ProgInfo *pinfo;
cr = gdk_cairo_create(widget->window);
pinfo = (ProgInfo *) data;
pos1x = gtk_adjustment_get_value (pinfo->adj[0]);
//Objecto
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_set_line_width (cr, 1.0);
cairo_rectangle (cr, (double) pos1x, (double) pos1y, 20, 80);
cairo_stroke_preserve (cr);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_fill (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_set_line_width (cr, 1.0);
cairo_rectangle (cr, (gint) pos3x, (gint) pos3y, 5, 80);
cairo_stroke_preserve (cr);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_fill (cr);
cairo_stroke(cr);
cairo_destroy(cr);
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window, *vbox, *vbox1, *frame, *frame1, *frame2, *label, *label1, *label2, *hbox, *hbox1, *hscale;
char string[40] = "Posição Objecto", string1[30] = "Posição Espelho";
ProgInfo *pinfo;
gdouble pos1x;
pinfo = (ProgInfo *) calloc (1, sizeof (ProgInfo));
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "expose-event", G_CALLBACK(on_expose_event), NULL);
g_signal_connect (window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title (GTK_WINDOW(window), "Projecto Óptica");
gtk_window_set_default_size (GTK_WINDOW(window), 800, 600);
gtk_widget_set_app_paintable (window, TRUE);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
hbox1 = gtk_hbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (vbox), hbox1);
vbox1 = gtk_vbox_new (FALSE, 0);
gtk_box_pack_end (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 20);
//Posição Objecto
label2 = gtk_label_new (string);
gtk_box_pack_start (GTK_BOX (vbox1), label2, FALSE, FALSE, 20);
pinfo->adj[0] = (GtkAdjustment *) gtk_adjustment_new (0.7, 0.0, 1.0, 0.001, 1.0, 0.0);
//Os parâmetros são, por ordem: valor inicial, valor mínimo e valor máximo
pinfo->scale[0] = gtk_hscale_new (GTK_ADJUSTMENT (pinfo->adj[0]));
gtk_box_pack_start (GTK_BOX (vbox1), pinfo->scale[0], FALSE, TRUE, 5);
//Posição Espelho
label1 = gtk_label_new (string1);
gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 20);
pinfo->adj[1] = (GtkAdjustment *)gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
pinfo->scale[1] = gtk_hscale_new (GTK_ADJUSTMENT (pinfo->adj[1]));
gtk_box_pack_start (GTK_BOX (vbox1), pinfo->scale[1], FALSE, FALSE, 0);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
I created a couple of sliders with the hscale widget, and they show up fine in the window, I can move them, everything's alright. But I want to make my variable, pos1x, change when I move the slider. I tried using the gtk_adjustment_get_value function to do it, but I'm getting a segmentation fault. I've noticed that if I comment out this line:
pos1x = gtk_adjustment_get_value (pinfo->adj[0]);
The segmentation fault does not happen anymore, but the app doesn't do what I want either. I realize that this is probably very simple, and my doubts derive from scarce understanding of how GTK+ works, but I've been trying for the last few hours and I can't figure out what's wrong. I'd appreciate any help you have to offer.
Oh, and sorry for putting such a big block of code here, but I wasn't sure which parts you'd need.
You connect to the expose-event here with the userdata pointer set to NULL:
g_signal_connect (window, "expose-event", G_CALLBACK(on_expose_event), NULL);
but in the handler you expect it to be a pointer to ProgInfo. You should replace NULL with pinfo.

GDK Threads not allowing gtk changes(Making timer)

#include <gtk/gtk.h>
#include<string.h>
#include<stdio.h>
#include <stdbool.h>
#include<stdlib.h>
static GtkWidget *textlabel_question_no;
static GtkWidget *textlabel_answer1;
static GtkWidget *textlabel_answer2;
static GtkWidget *textlabel_answer3;
static GtkWidget *textlabel_answer4;
static GtkWidget *textlabel_question;
static GtkWidget *textlabel_timer;
static GtkWidget *textlabel_timeleft;
static GtkWidget *button_next;
static GtkWidget *window2;
static GtkWidget *window31;
static GThread *thread;
void show_info(GtkWidget *window2);
// thread for timer
static gpointer thread_Func(gpointer data)
{
// gdk_threads_enter();
int min=0,sec;//min=29
while(min > -1 )
{
sec = 10;
while(sec>=0)
{
sleep(1);
char* timer_text=malloc(sizeof(char)*40);
if(sec>9)
{
sprintf(timer_text,"%d : %d",min,sec);
}
else
{
sprintf(timer_text,"%d : 0%d",min,sec);
}
gtk_label_set_text(GTK_LABEL(textlabel_timer),timer_text);
sec--;
}
min--;
}
// gdk_threads_leave();
// gdk_threads_enter();
g_printf("in show_info\n");
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(window2),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Your Time is UP !!!\n Lets see the Result & Statistics...","title");
gtk_window_set_title(GTK_WINDOW(dialog), "Time Finished");
gint result=gtk_dialog_run(GTK_DIALOG(dialog));
switch(result)
{
case GTK_RESPONSE_OK:
gtk_widget_hide(window2);
g_printf("in show_info\n");
system("./result &");
//gtk_main_quit();
break;
}
//sleep(10);
gtk_widget_destroy(dialog);
/*
window31 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window31), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window31), "Examination Panel");
gtk_container_set_border_width(GTK_CONTAINER(window31),12);
gtk_window_set_resizable(GTK_WINDOW(window31),FALSE);
gtk_widget_set_size_request(window31,300,150);
gtk_widget_show_all(window31);
//sleep(10);
gdk_threads_leave();*/
return NULL;
}
static void next_question_label_change(GtkWidget *button_next,gpointer data)
{
g_printf("in button_next\n");
static int question_value=2;
char *question_label = malloc(sizeof(char)*50);
sprintf(question_label,"Question %d of 10.",question_value);
gtk_label_set_text(GTK_LABEL(textlabel_question_no),question_label);
if(question_value<10)
question_value++;
}
//For Submit button dialog box
static void test_submit_window(GtkWidget *button_next,GtkWidget *window2)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(window2),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"Are you sure to Submit the Test?");
gtk_window_set_title(GTK_WINDOW(dialog), "Submit Test Confirmation");
gint result = gtk_dialog_run (GTK_DIALOG (dialog));
switch(result)
{
case GTK_RESPONSE_YES:
system("./result &");
gtk_widget_hide(window2);
break;
case GTK_RESPONSE_NO:
break;
}
gtk_widget_destroy(dialog);
}
int
main (int argc,char *argv[])
{
GTimer *g_time;
GtkWidget *fixed;
GtkWidget *radio1,*radio2,*radio3,*radio4;
GtkWidget *button_submit;
GtkWidget *textlabel_title;
GtkWidget *image;
GtkWidget *image2;
GError *error = NULL;
GdkPixbuf *pixbuf;
GtkWidget *scrolled_window;
/* Secure glib */
if( ! g_thread_supported() )
g_thread_init( NULL );
//g_threads_init(NULL);
//g_thread_init(NULL);
/* Secure gtk */
gdk_threads_init();
/* Obtain gtk's global lock */
// intialiazation
gtk_init (&argc, &argv);
//window attributes position,size,title
window2 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window2), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window2), "Examination Panel");
gtk_container_set_border_width(GTK_CONTAINER(window2),12);
gtk_window_set_resizable(GTK_WINDOW(window2),FALSE);
gtk_widget_set_size_request(window2,800,450);
button_next = gtk_button_new_with_label("Next>>");
button_submit = gtk_button_new_with_label("Submit");
textlabel_title = gtk_label_new("-> TECHNICAL EXAM <-");
textlabel_question = gtk_label_new("question placed here");
textlabel_question_no = gtk_label_new(" Question 1 of 10.");
textlabel_answer1 = gtk_label_new(" answer 1");
textlabel_answer2 = gtk_label_new(" answer 2");
textlabel_answer3 = gtk_label_new(" answer 3");
textlabel_answer4 = gtk_label_new(" answer 4");
textlabel_timer = gtk_label_new("30:00");
textlabel_timeleft = gtk_label_new("Time Left :");
//radio button for option
radio1 = gtk_radio_button_new_with_label (NULL , "A. ");
radio2 = gtk_radio_button_new_with_label_from_widget
(GTK_RADIO_BUTTON(radio1),"B.");
radio3 = gtk_radio_button_new_with_label_from_widget
(GTK_RADIO_BUTTON (radio1),"C. ");
radio4 = gtk_radio_button_new_with_label_from_widget
(GTK_RADIO_BUTTON (radio1),"D. ");
// For image
pixbuf = gdk_pixbuf_new_from_file_at_size
("/home/trilok/trantorlogo.png", 100, 100, &error);
if(!pixbuf)
{
g_print ("Error: %s\n",error->message);
g_error_free (error);
/* Handle error here */
}
image = gtk_image_new_from_pixbuf(pixbuf);
image2 = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref (pixbuf);
//For Signals
g_signal_connect (window2, "destroy", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (button_next,"clicked",G_CALLBACK
(next_question_label_change), NULL);
g_signal_connect (button_submit,"clicked",G_CALLBACK(test_submit_window),window2);
//timer
// pthread_create(&pth,NULL,threadFunc,"foo");
/* Create new thread */
thread = g_thread_create( thread_Func,NULL,
FALSE,&error);
if( ! thread )
{
g_print( "Error: %s\n", error->message );
return( -1 );
}
// For scrolled window
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window),10);
gtk_scrolled_window_set_policy
(GTK_SCROLLED_WINDOW
(scrolled_window)
,GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
//fixed
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window2), fixed);
gtk_widget_show(fixed);
gtk_scrolled_window_add_with_viewport
(GTK_SCROLLED_WINDOW(scrolled_window),textlabel_question);
gtk_widget_set_size_request(scrolled_window,580,150);
//scrolled border
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_CORNER_TOP_LEFT);
gtk_fixed_put(GTK_FIXED(fixed), scrolled_window, 70, 110);
gtk_fixed_put(GTK_FIXED(fixed), image, 0, 0);
gtk_fixed_put(GTK_FIXED(fixed), image2, 0, 510);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_title, 300, 20);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_timeleft, 610, 70);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_timer, 690, 70);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_question_no, 65, 70);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_answer1,170, 300);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_answer2,170, 350);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_answer3,170, 400);
gtk_fixed_put(GTK_FIXED(fixed), textlabel_answer4,170, 450);
gtk_fixed_put(GTK_FIXED(fixed), radio1, 100,300);
gtk_fixed_put(GTK_FIXED(fixed), radio2, 100,350);
gtk_fixed_put(GTK_FIXED(fixed), radio3, 100,400);
gtk_fixed_put(GTK_FIXED(fixed), radio4, 100,450);
gtk_fixed_put(GTK_FIXED(fixed), button_next,620, 500);
gtk_fixed_put(GTK_FIXED(fixed), button_submit,690, 500);
gtk_widget_show_all(window2);
//gdk_threads_enter();
GDK_THREADS_ENTER();
gtk_main();
/* Release gtk's global lock */
//gdk_threads_leave();
GDK_THREADS_LEAVE();
return 0;
}
Actually i am making an timer on exam simulator . My timer is working correctly but the problem is this i have to open an dialog box when timer goes to 0:00. her i am have implemented the threads to make an timer. Problem is this when timer goes to 0:00 then i segmentation fault. the gdk thread is not allowing any call to gtk widget.
Thanks for the help in advance.
Some rectify the above code an make it happen will be appreciated
It's not clear if you're using gdk_threads_enter() or not, since there's a bunch of commented-out calls and a macro instead. GTK+ is not thread-safe, what you're trying is not the proper way.
You really shouldn't need a thread for this, just use a glib timer.
You're leaking the memory from the timer_text allocation; gtk_label_set_text() does not transfer ownership of the text buffer (notice that it's const).

Resources