Create a Rounded image in gtk - c

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

Related

GTK3: Resize Image while retaining aspect-ratio

When I'm resizing the GtkWindow, i want the GtkImage to resize as well while keeping the same aspect ratio as before.
I can't find any good examples on how to set this up with GTK3
This is what i've tried so far:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
GtkAllocation *allocation = g_new0 (GtkAllocation, 1);
gboolean resize_image(GtkWidget *widget, GdkEvent *event, GtkWidget *window) {
GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(widget));
if (pixbuf == NULL) {
g_printerr("Failed to resize image\n");
return 1;
}
gtk_widget_get_allocation(GTK_WIDGET(widget), allocation);
pixbuf = gdk_pixbuf_scale_simple(pixbuf, widget->allocation.width, widget->allocation.height, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
return FALSE;
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
GtkWidget *image = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
image = gtk_image_new_from_file("image.jpg");
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(image, "draw", G_CALLBACK(resize_image), (gpointer)window);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
This code should just resize the Pixbuf to the size of the parent, but it doesn't work, i get these errors:
GdkPixbuf-CRITICAL **: gdk_pixbuf_get_width: assertion 'GDK_IS_PIXBUF
(pixbuf)' failed
GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT
(object)' failed
Even if this code would work, i wouldn't be able to keep the same aspect ratio, how to achieve this?
Thanks in Advance
Well, a trick to do this is using a GtkLayout between the image and the window.
Also, instead of using the draw signal, use the size-allocate signal.
We will load a GdkPixbuf and use it as reference for scaling, otherwise the quality would deteriorate with cumulative 'resizing'.
A simple approach would be:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
struct _resize_widgets {
GtkWidget *image;
GdkPixbuf *pixbuf;
};
typedef struct _resize_widgets ResizeWidgets;
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) {
int x,y,w,h;
GdkPixbuf *pxbscaled;
GtkWidget *image = (GtkWidget *) ((ResizeWidgets *) user_data)->image;
GdkPixbuf *pixbuf= (GdkPixbuf *) ((ResizeWidgets *) user_data)->pixbuf;
x = 0;
y = 0;
h = allocation->height;
w = (gdk_pixbuf_get_width(pixbuf) * h) / gdk_pixbuf_get_height(pixbuf);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR);
if (w < allocation->width) {
x = (allocation->width - w) / 2;
gtk_layout_move(GTK_LAYOUT(widget), image, x, y);
}
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
return FALSE;
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
GtkWidget *image = NULL;
GtkWidget *container = NULL;
GdkPixbuf *pixbuf = NULL;
ResizeWidgets *widgets;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
container = gtk_layout_new(NULL, NULL);
image = gtk_image_new();
pixbuf = gdk_pixbuf_new_from_file ("image.png", NULL);
if (pixbuf == NULL) {
g_printerr("Failed to resize image\n");
return 1;
}
widgets = g_new0(ResizeWidgets, 1);
widgets->image = image;
widgets->pixbuf = pixbuf;
gtk_container_add(GTK_CONTAINER(window), container);
gtk_layout_put(GTK_LAYOUT(container), image, 0, 0);
gtk_widget_set_size_request (GTK_WIDGET(window), 20, 20);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(container, "size-allocate", G_CALLBACK(resize_image), widgets);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
g_object_unref (pixbuf);
g_free(widgets);
return 0;
}
Compile with gcc -o main main.cpkg-config --cflags --libs gtk+-3.0`
This will keep aspect ratio. If that is not desired, then the resize_image callback handler would be:
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) {
int x,y,w,h;
GdkPixbuf *pxbscaled;
GtkWidget *image = (GtkWidget *) ((ResizeWidgets *) user_data)->image;
GdkPixbuf *pixbuf= (GdkPixbuf *) ((ResizeWidgets *) user_data)->pixbuf;
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, allocation->width, allocation->height, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
return FALSE;
}
This is a simple hack, there are other options obviously, like cairo for drawing or simply checking Eye of Gnome (eog) implementation which is much more complete.

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.

How do I make a GTK3 image-in-a-window shrinkable?

I have a simple GTK3 app that displays an image from a file in a window.
When you resize the window, the image is scaled in the expose callback to fit the window.
However, once the window has grown, you can't shrink it again; the resize handles only let you make the window ever bigger.
With GTK2 it was trivial to allow grow and shrink with gtk_window_set_policy(w,1,1,1).
How can the same effect be achieved in GTK3?
Here's the ever-growing code example:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
gboolean resize_image(GtkWidget *widget, GdkEvent *event, void *data)
{
GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(widget));
if (pixbuf == NULL)
{
g_printerr("Failed to get pixbuf\n");
return 1;
}
pixbuf = gdk_pixbuf_scale_simple(pixbuf,
widget->allocation.width, widget->allocation.height,
GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
return FALSE;
}
int main(int argc, char **argv)
{
GtkWidget *window = NULL;
GtkWidget *image = NULL;
if (argc < 2 || argc > 3)
{
g_printerr("Usage: %s <image>\n", argv[0]);
return 1;
}
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
image = gtk_image_new_from_file(argv[1]);
if (image == NULL)
{
g_printerr("Could not open \"%s\"\n", argv[1]);
return 1;
}
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(image, "expose-event", G_CALLBACK(resize_image), NULL);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
Eric Cecashon on the gtk-list mailing list suggests using a cairo drawing area inside a 1x1 grid container, which works fairly well:
/*
gcc -Wall da_resize.c -o da_resize `pkg-config gtk+-3.0 --cflags --libs`
Tested on Ubuntu16.04, GTK3.18.
*/
#include<gtk/gtk.h>
gboolean draw_picture(GtkWidget *da, cairo_t *cr, gpointer data)
{
gint width=gtk_widget_get_allocated_width(da);
gint height=gtk_widget_get_allocated_height(da);
GdkPixbuf *temp=gdk_pixbuf_scale_simple((GdkPixbuf*)data, width, height, GDK_INTERP_BILINEAR);
gdk_cairo_set_source_pixbuf(cr, temp, 0, 0);
cairo_paint(cr);
g_object_unref(temp);
return FALSE;
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Resize Picture");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
//Needs a valid picture.
GdkPixbuf *pixbuf=gdk_pixbuf_new_from_file(argc>1 ? argv[1] : "image.jpg", NULL);
GtkWidget *da1=gtk_drawing_area_new();
gtk_widget_set_hexpand(da1, TRUE);
gtk_widget_set_vexpand(da1, TRUE);
g_signal_connect(da1, "draw", G_CALLBACK(draw_picture), pixbuf);
GtkWidget *grid=gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid), da1, 0, 0, 1, 1);
gtk_container_add(GTK_CONTAINER(window), grid);
gtk_widget_show_all(window);
gtk_main();
g_object_unref(pixbuf);
return 0;
}

C LIBCHAMPLAIN SegFault?

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.

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