GTK get multiple range value segmentation error - c

So, I'm trying to create an rgb selector with gtk in C.
I follow the documentation to learn how to put in place a glade project and use it with gtk, so I made an UI in glade, but I have some trouble with the GTK part. I need to have access to multiple slider in the change-value signal because I want to get their value to print them, so I have created a struct to stock them, and I send this struct in the signal. But my problem is when I try to get the value of the range which his stock in the struct I have a segmentation error and I don't know why. I tried without the struct and I can correctly get the slider value, but it didn't work with the struct. How can I fix it?
Ask me if you need the glade file too.
//Compil : gcc -rdynamic -o ColorPicker colorPicker.c `pkg-config --cflags --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <glib/gstdio.h>
#include <gdk/gdk.h>
typedef struct
{
GObject *redSlider;
GObject *blueSlider;
GObject *greenSlider;
GObject *label;
}Data;
static void changeLabel (GtkWidget *range, Data *data)
{
gdouble red = gtk_range_get_value(GTK_RANGE(data->redSlider));
g_print("%.0lf\n",red);
//g_print("R : %d, G : %d, B : %d",red,green,blue);
}
static void activate(GtkApplication *app, gpointer user_data)
{
Data *data;
data = malloc(sizeof(*data));
GtkBuilder *builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "colorPicker.glade",NULL);
GObject *window = gtk_builder_get_object (builder, "window");
gtk_window_set_application (GTK_WINDOW (window), app);
data->redSlider = gtk_builder_get_object (builder, "redSlider");
g_signal_connect (data->redSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->blueSlider = gtk_builder_get_object (builder, "blueSlider");
g_signal_connect (data->blueSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->greenSlider = gtk_builder_get_object (builder, "greenSlider");
g_signal_connect (data->greenSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->label = gtk_builder_get_object (builder, "cpChooseLabel");
/*GObject *colorBtn = gtk_builder_get_object (builder, "colorBtn");
g_signal_connect (colorBtn, "clicked", G_CALLBACK (getColor), (gpointer) data);*/
gtk_widget_show (GTK_WIDGET (window));
/* We do not need the builder any more */
g_object_unref (builder);
free(data);
}
int main(int argc, char **argv)
{
#ifdef GTK_SRCDIR
g_chdir(GTK_SRCDIR);
#endif
GtkApplication *app = gtk_application_new("com.github.XXXXXX.rgbSelector", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

You end the structure's lifetime by freeing it at the end of activate. When the callback changeLabel is invoked at some time later, it tries to access the no longer existing structure. You could just drop the free(data); if you don't care that the space occupied by the four pointers can't be freed then; another possibility is to simply use a static structure and pass its address.

Related

Changing background color of GtkEntry

I have written a C language program with many GtkEntry's for data input. I have created the UI using Glade and the GtkEntrys emit an on_entry#_changed() signal when modified. My program checks the validity of the input, which has certain requirements. e.g., must be valid hexadecimal.
I would like the background of a GtkEntry to go red while it is invalid, and turn back to the original color when acceptable. The original color is dependent upon the desktop style set by the user. For example, on Ubuntu, I'm using a "Dark" style, so the box is dark gray.
What is the best way to implement this background color switching so that it applies to an individual GtkEntry and renders the user's chosen style color when the data is ok? I see a lot of discussion out there but it is often using deprecated functions.
You can use the error style class to mark the entry as having error. The following is a minimal example that checks if an entry has a valid hex digit and updates the entry style:
/* main.c
*
* Compile: cc -ggdb main.c -o main $(pkg-config --cflags --libs gtk+-3.0) -o main
* Run: ./main
*
* Author: Mohammed Sadiq <www.sadiqpk.org>
*
* SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
*/
#include <gtk/gtk.h>
static void
entry_changed_cb (GtkEntry *entry)
{
GtkStyleContext *style;
const char *text;
gboolean empty;
g_assert (GTK_IS_ENTRY (entry));
style = gtk_widget_get_style_context (GTK_WIDGET (entry));
text = gtk_entry_get_text (entry);
empty = !*text;
/* Loop until we reach an invalid hex digit or the end of the string */
while (g_ascii_isxdigit (*text))
text++;
if (empty || *text)
gtk_style_context_add_class (style, "error");
else
gtk_style_context_remove_class (style, "error");
}
static void
app_activated_cb (GtkApplication *app)
{
GtkWindow *window;
GtkWidget *entry;
window = GTK_WINDOW (gtk_application_window_new (app));
entry = gtk_entry_new ();
gtk_widget_set_halign (entry, GTK_ALIGN_CENTER);
gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (window), entry);
g_signal_connect_object (entry, "changed",
G_CALLBACK (entry_changed_cb),
app, G_CONNECT_AFTER);
entry_changed_cb (GTK_ENTRY (entry));
gtk_window_present (window);
}
int
main (int argc,
char *argv[])
{
g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
return g_application_run (G_APPLICATION (app), argc, argv);
}

Why do I get a segmentation fault in my GTK+ signal callback?

I am trying to measure the size of a GTK label:
#include <gtk/gtk.h>
static void map_event(GtkWidget *window, gpointer lab) {
g_print( "In the callback..\n" );
GtkWidget *label = GTK_WIDGET(lab);
g_print( "Everything is ok..\n" );
}
static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window1");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 280);
GtkWidget *grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
GtkWidget *label = gtk_label_new("Hello world!");
gtk_grid_attach(GTK_GRID (grid), label, 0,0,1,1);
g_signal_connect (window, "map-event", G_CALLBACK(map_event), label);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app = gtk_application_new (
"org.gtk.example", G_APPLICATION_FLAGS_NONE );
g_signal_connect( app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref (app);
return status;
}
This gives output:
In the callback..
Segmentation fault (core dumped)
If I comment out the line:
GtkWidget *label = GTK_WIDGET(lab);
there is no segmentation fault, the label shows up and the output is:
In the callback..
Everything is ok..
What am I missing here?
map-event has following signature, so you are missing GdkEvent* argument:
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
Unfortunately, GTK+ is written in C, so it lacks type-safe callback functions, so it's easy to make mistakes such as this.
You don't respect the signal signature. Each signal is associated with a pre-defined function prototype you must respect, otherwise you'll just read garbage. Here you just made up out of your mind the callback signature so things won't work as expected.
The signal is like a delicious fruit delivery service. By connecting to that signal, you signed a contract that subscribe you to the fruit delivery service. Fruit will be delivered only when the fruit is ripe. The delivery man will:
come in front of your home
drop some fruit boxes for you
knock at your door
go back to its truck
The contract also specifies that:
box #1 will contain bananas
box #2 will contain apples
box #3 will contain oranges
Those boxes are like the arguments of your callback. The map-event takes 3 arguments, thus the 3 boxes.
One day, you hear knocking at the door. You open the door, see the boxes, open box #2 and get annoyed saying "damn, I said I wanted oranges!". The thing is that you're mixing apples and oranges: by contract, oranges are in box #3 and you're looking for them in box #2.
So give a look at the documentation of each signal you want to connect to. That's the only way to write the right callback. Here you forgot one input parameter as well as the return value. In the case of map-event, that return value can be seen as you going to the truck to say if you want to continue or stop the deliveries.

GTK+ Threading with OpenGL's GLUT/FreeGLUT

I am fairly new to C/C++ programming, so please excuse me if something sounds stupid to you...
I am currently working on a Visual Studio C++ 2010 project that involves opengl, glut/freeglut, and gtk+.
The OpenGL is used to take an input image, manipulate its pixels based on various parameters before calling glDrawPixels() to draw the pixels from buffer for display in a glut/freeglut window.
Now I am trying to make a UI so user can adjust the parameters and see the resulting image at runtime.
What I have so far is one GTK window that contains all of the GTK widgets, and a glut/freeglut window that houses the OpenGL image. How it works is that when the button on the UI is clicked, a new GTK thread is created to display the glut/freeglut window (that contains the OpenGL rendered image.
My question is, how do I make glut/freeglut to render updated OpenGL image and display it in the same glut/freeglut window? I am not sure if it has to do with GTK threading or it's just glut/freeglut, or both. Does anyone have any advice?
Here's the stripped down code I have:
#include<freeglut.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <gtk/gtk.h>
GtkWidget *window;
GtkWidget *vbox, *hbox;
GtkWidget *button;
gint tmp_pos;
GThread *thread;
gint progress = 0;
G_LOCK_DEFINE_STATIC(progress);
GError *error = NULL;
void display()
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glRasterPos2i(x_offset,y_offset);
glDrawPixels(x2-x1+1,y2-y1+1,GL_LUMINANCE,GL_UNSIGNED_BYTE,tmp_buf);
glFlush();
}
static gpointer runGL(gpointer data)
{
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
if(Running_Mode==0)
glutInitWindowSize(3*Test_Size,Test_Size); /* 500 x 500 pixel window */
else
glutInitWindowSize(Test_Size,Test_Size); /* 500 x 500 pixel window */
glutInitWindowPosition(600,0); /* place window top left on display */
glutCreateWindow("Simulation"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
return (NULL);
}
/* create a g_thread for glut window */
void GLThread()
{
thread = g_thread_create(runGL, (gpointer)button, TRUE, &error);
g_print("Thread created");
if(!thread)
{
g_print("Error: %s\n", error->message);
return(-1);
}
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
if(! g_thread_supported())
g_thread_init( NULL );
gdk_threads_init();
/* Obtain gtk's global lock */
gdk_threads_enter();
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect_swapped (window, "delete-event",
G_CALLBACK (gtk_widget_destroy),
window);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);
hbox = gtk_hbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
gtk_widget_show (hbox);
button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
/* call the GLThread function when the button is clicked */
g_signal_connect_swapped (button, "clicked", G_CALLBACK (GLThread), window);
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
gtk_widget_set_can_default (button, TRUE);
gtk_widget_show (button);
gtk_widget_show(window);
gtk_main();
gdk_threads_leave();
}
First things first: Free-/GLUT is not a part of OpenGL. It's a 3rd party library with a similar scope (just much more simpler) like GTK+. If you're using GTK+ you don't need GLUT. Instead you should use the GTK+ OpenGL Widget provided by GTKGlExt.
I am currently working on a Visual Studio C++ 2010 project that involves opengl, glut/freeglut, and gtk+.
Why would you want to mix GLUT and GTK+? There's absolutely no sane reason to do this. GLUT is a simple application framework (creates windows, provides the event loop), GTK+ is an application framework (creates windows, provides the event loop, has widgets).
Choose one, don't mix them.
I am not sure if it has to do with GTK threading or it's just glut/freeglut, or both. Does anyone have any advice?
The problem is, that you have two libraries fighting to do the same thing (processing user input events).

Gtk change multiple labels on button click

How can i change multible label values on single button click.Normally on a button click signal connect we can give only one user data.
Example code
void show_loop(GtkWidget *widget, gpointer user_data)
{
char buf[5];
int no = TxBuf.plBuf[7];
sprintf(buf, "%d",no);
gtk_label_set_text(GTK_LABEL(user_data), buf);
}
ID_label=GTK_WIDGET (gtk_builder_get_object (builder, "label24"));
DLC_label=GTK_WIDGET (gtk_builder_get_object (builder, "label25"));
check = GTK_WIDGET (gtk_builder_get_object (builder, "button3"));
g_signal_connect (check, "clicked", G_CALLBACK (show_loop), DLC_label);
I want to change both the labels on single button click.
Typically you would define, allocate and fill a struct that contains all the widgets that may have to be changed dynamically in your initialization code:
typedef struct AppData {
GtkWidget *id_label;
GtkWidget *dlc_label;
} AppData;
...
AppData *app_data = g_new0 (AppData, 1);
app_data->id_label = GTK_WIDGET (gtk_builder_get_object (builder, "label24"));
app_data->dlc_label = GTK_WIDGET (gtk_builder_get_object (builder, "label25"));
The you use the app_data as userdata parameter and can access the widgets inside the signal handler as e.g. app_data->id_label.

How to Implement a button-press-event on GtkTable

Searching the web for answers dosen't get me through my problem:
I wan't my GtkTable to throw an event, if i click one cell.
Since there is no click event, accept for GtkButton's, i wanted to implement a GDK_BUTTON_PRESS_MASK and GDK_BUTTON_RELEASE_MASK to catch the position of the mouse on the Table during click.
Works great with GtkDrawingArea!
Tryed the snipet bellow, but nothing happend, maybe someone can give me a clue :)
little sample:
static void table_press(GtkWidget *widget, GdkEventButton *event)
{
printf("table pressed");
}
int main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget* table;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "table click");
table = gtk_table_new(2, 5, TRUE);
gtk_container_add(GTK_CONTAINER (window), table);
gtk_widget_add_events(table, GDK_BUTTON_PRESS_MASK);
g_signal_connect(GTK_OBJECT (table), "button-press-event",
G_CALLBACK (table_press), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
main_exit();
return 0;
}
You don't receive events because GtkTable does not have a GdkWindow associated with it. You can use GtkEventBox which lets you accept events on widgets that would not normally accept events. This is derived from GtkBin so the interesting code would look like this.
table = gtk_table_new(2, 5, TRUE);
event_box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER (window), event_box);
gtk_container_add(GTK_CONTAINER (event_box), table);
g_signal_connect(GTK_OBJECT (event_box), "button-press-event",
G_CALLBACK (table_press), NULL);

Resources