call external functions in GTK+ gui - c

Am having a main.c which is linked with some headers and other c files.After completing the program its a terminal based program which works with user input using switch.Its associated with a hardware board when i gives "o" it opens and "c" it closes.
I got a sample GTK+ gui code written in c with open cloase and quit buttons.How would i link my open and close functions with the open and cloase buttons in gui.
This is the GTK Code am Having
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
int
main (int argc,
char *argv[])
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application.
*/
gtk_init (&argc, &argv);
/* create a new window, and set its title */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "CANMate");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 50);
/* Here we construct the container that is going pack our buttons */
grid = gtk_grid_new ();
/* Pack the container in the window */
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Open");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
/* Place the first button in the grid cell (0, 0), and make it fill
* just 1 cell horizontally and vertically (ie no spanning)
*/
gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
button = gtk_button_new_with_label ("Close");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
/* Place the second button in the grid cell (1, 0), and make it fill
* just 1 cell horizontally and vertically (ie no spanning)
*/
gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);
button = gtk_button_new_with_label ("Quit");
g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
/* Place the Quit button in the grid cell (0, 1), and make it
* span 2 columns.
*/
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
/* Now that we are done packing our widgets, we show them all
* in one go, by calling gtk_widget_show_all() on the window.
* This call recursively calls gtk_widget_show() on all widgets
* that are contained in the window, directly or indirectly.
*/
gtk_widget_show_all (window);
/* All GTK applications must have a gtk_main(). Control ends here
* and waits for an event to occur (like a key press or a mouse event),
* until gtk_main_quit() is called.
*/
gtk_main ();
return 0;
}

In the line
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
you are "connecting" a "signal handler": specifying that when button is clicked (that is, it emits the "clicked" signal), the function print_hello() should be called.
Just replace print_hello() with your open or close function, in the appropriate call for the open or close button.
EDIT: Passing parameters to the function
The signal handler is expected to have a prototype of the form:
void signal_handler (GtkButton *button, void *user_data)
The button parameter gets the button that was clicked, and user_data gets whatever you specified as the last parameter of g_signal_connect() -- in this case, NULL.
If you want to pass parameters to your open or close function, you will have to write an adapter function, such as the following:
void
on_open_click (GtkButton *open_button, void *user_data)
{
if (my_open_function (my_parameter_1, my_parameter_2) == UH_OH_ERROR) {
fprintf(stderr, "Something went wrong.\n");
}
And then connect it with g_signal_connect() instead of print_hello:
g_signal_connect (button, "clicked", G_CALLBACK (on_open_click), NULL);
In this case, my_parameter_1 and my_parameter_2 can be literal values, or global variables. You can also connect the signal in such a way that you can get values for these parameters through the user_data parameter in your signal handler. It's hard to say whether you need to do that, without knowing more about your open and close functions.

Related

Why isnt the gtk dialog box closing even tho i use gtk_destoy_widget?

I am opening a dialog box then calling gtk_destroy_widget ,yet when I hit a button in the dialog box it stays instead of closing.
here is my code
GtkDialogFlags flags = GTK_DIALOG_MODAL;
GtkWidget *dialog = gtk_message_dialog_new (NULL,flags,GTK_MESSAGE_QUESTION,GTK_BUTTONS_YES_NO,"Are you sure you want to clear all ?");
int result = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy(dialog);
if(result != GTK_RESPONSE_YES) return;
I have also tired doing it a other like
g_signal_connect_swapped (dialog, "response",G_CALLBACK (gtk_widget_destroy), dialog);
but this didn't work either.
I've tried changing the flags variable To GTK_DIALOG_DESTROY_WITH_PARENT.
After receiving your comment response back I think I better understand how you had set up your code by defining and executing the dialog widget directly within your "main" function. I don't know if I built the code exactly as you did, but I did get the program to compile. When I tested it I did have a similar undesired behavior of the process remaining open even though the dialog widget did disappear. I had to manually kill the process.
Customarily, a GTK dialog works in the context of some type of GTK application which utilizes either a window or application window. So the dialog widget (or widgets) get built and reference the window as its parent. To illustrate that in as simple of a manner as I could, I created a minimal code example you could test out to see the relation of dialog widget and window.
#include <gtk/gtk.h>
static void helloWorld (GtkWidget *wid, GtkWidget *win)
{
GtkDialogFlags flags = GTK_DIALOG_MODAL;
/* NULL will work in lieu of GTK_WINDOW(win) below but it is customary to associate the dialog widget to a parent window */
GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(win),flags,GTK_MESSAGE_QUESTION,GTK_BUTTONS_YES_NO,"Are you sure you want to clear all ?");
int result = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy(dialog);
if(result != GTK_RESPONSE_YES) return;
}
int main (int argc, char *argv[])
{
GtkWidget *win = NULL;
gtk_init (&argc, &argv);
/* Create the main window */
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (win), "Just a Dialog");
g_signal_connect (win, "destroy", gtk_main_quit, NULL);
g_signal_connect (G_OBJECT (win), "realize", G_CALLBACK (helloWorld), (gpointer) win);
gtk_widget_realize (win);
/* Enter the main loop */
gtk_widget_show_all (win);
gtk_main ();
return 0;
}
With that, when the program is executed, your dialog appears.
When a button is clicked, the parent window will still be on the screen.
If all you are after is to display a dialog and have the program finish, you could probably add the emission of a "destroy" signal for the window after a response is selected in the dialog box, but as I noted, GTK dialog widgets are normally associated with a GTK application which has an associated window that is closed by the user when done with the application.
I hope this has given you food for thought.
Regards.

gtk_widget_show_all(window); not working when waiting on a function to return a value

I am making a dart game, and I have created the whole layout of the game page. I want to await a dart hitting the board, which can take a variable amount of time, then update the score for that dart, update the remaining points the player has left, and update the round score.
I make the layout, call gtk_widget_show_all(window);, then call await_dart_hit();
The window does not show until the dart hits though. It's as if the window can't show until the whole function ends, but I have tried making the window in a separate function, then returning, then calling await_dart_hit(); and this doesn't work either.
#include <gtk/gtk.h>
void problem_causing_wait(){
while(1);
}
void start(){
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Start");
gtk_container_set_border_width(GTK_CONTAINER(window),10);
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
gtk_widget_show_all(window);
problem_causing_wait();
}
int main(int argc, char *argv[]) {
GtkWidget *window, *button, *button_box;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Welcome!");
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window),button_box);
button = gtk_button_new_with_label("Get Started");
g_signal_connect (button, "clicked", G_CALLBACK (start), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add(GTK_CONTAINER(button_box),button);
gtk_widget_show_all(window);
gtk_main();
return(0);
}
If you run this code, you'll see that once you click the "Get Started" button, it freezes. It doesn't show the "Start" window despite showing all before calling the problem_causing_wait() function.
Please help!
compiled with: gcc main.c -o main pkg-config --cflags --libs gtk+-3.0
As your application is running in a single thread this function "problem_causing_wait" acts as a blocking function and stops the main loop.
i think using "g_idle_add" and "g_thread_new" might solve your problem.
#include <gtk/gtk.h>
void *problem_causing_wait(){
while(1);
//update the Ui using g_idle_add
return NULL;
}
void start(){
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Start");
gtk_container_set_border_width(GTK_CONTAINER(window),10);
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
g_thread_new("dart-game",problem_causing_wait,NULL);
gtk_widget_show_all(window);
}
int main(int argc, char *argv[]) {
GtkWidget *window, *button, *button_box;
//Initilizes Support for Concurrent Threads
XInitThreads();
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Welcome!");
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window),button_box);
button = gtk_button_new_with_label("Get Started");
g_signal_connect (button, "clicked", G_CALLBACK (start), NULL);
//g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add(GTK_CONTAINER(button_box),button);
gtk_widget_show_all(window);
gtk_main();
return(0);
}
You're not supposed to freeze the UI. Freezing the UI means no refresh, even if a refresh is needed. For example if you move another application on the foreground, then move it away, your app still has to repaint. You also can't show a countdown of the time remaining to shoot the dart. Due to that, you can't handle cases when a player completely misses the target (here, you should probably either interact with the UI or let the turn countdown expire with some feedback).
Instead, don't use threads at all, and use g_timeout_add to check every 500ms if a dart hit the board, letting the GTK+ main loop handle the polling of your I/O.

Show GtkApplicationWindow after close

I am a complete newbie when it comes to C and Gtk+.
I am trying to create an interface with a main application window. This main window has a menu, which opens a second window (of type GtkApplictionWindow).
My problem is, that once I close this second window (with the x in the top) I cannot open this second window again.
I get an error:
(api:2807): Gtk-CRITICAL **: gtk_widget_show: assertion 'GTK_IS_WIDGET (widget)' failed
I've tried attaching a function to both the destroy and the hide signals, and in my code I've tried both gtk_widget_destroy(window_connections) and gtk_widget_hide(window_connections).
My interface is created in Glade.
Here is my current code:
#include <gtk/gtk.h>
#include <stdio.h>
GtkWidget *window_connections;
int main(int argc, char *argv[]) {
GtkBuilder *builder;
GtkWidget *window;
GtkWidget *statusbar;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "glade/window_main.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
gtk_builder_connect_signals(builder, NULL);
window_connections = GTK_WIDGET(gtk_builder_get_object(builder, "window_connections"));
statusbar = GTK_WIDGET(gtk_builder_get_object(builder, "statusbar"));
gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, "Hello, World!");
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
return 0;
}
// called when window is closed
void on_window_main_destroy() {
gtk_main_quit();
}
void window_open_connections() {
gtk_widget_show(window_connections);
}
void window_close_connections() {
gtk_widget_hide(window_connections);
}
void window_hide_test() {
printf("hide\n");
}
Help?
If you close a Window using the "X", it will be not only hidden but also destroyed afterwards.
Obviously you cannot reuse that widget later. You would need to create it again.
This is where gtk_widget_hide_on_delete() comes in handy.
You can directly connect it to the "delete-event" signal or you can call it from within your handler for that signal.
Then the widget is only hidden but can be shown again later.

How to get webcam feed to GTK window?

I need to get webcam video feed using C, GTK2/3, Cairo.
However can't find any references about it.
Below shows how did I try using opencv. It is unsuccessful.I need to know some other method using gstreamer, cairo.
I'm expecting simple code to get video to GTK window. Really appreciate if someone can provide example code.
/*
gcc -o weby3 att3.c `pkg-config --libs --cflags gtk+-2.0 opencv`
*/
#include "highgui.h"
#include <gtk/gtk.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
GdkPixbuf* pix;
IplImage* frame;
CvCapture* capture;
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
while(1) {
frame = cvQueryFrame( capture );
if(!frame) break;
pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
frame->height, (frame->widthStep), NULL, NULL);
gdk_draw_pixbuf(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
-1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */
char c = cvWaitKey(33);
if( c == 27 ) break;
}
cvReleaseCapture( &capture );
return TRUE;
}
int main( int argc, char** argv ) {
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
CvCapture* capture = cvCreateCameraCapture(0);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hello WebCam and OpenCV!");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Now add a child widget to the aspect frame */
drawing_area = gtk_drawing_area_new();
/* window since we are forcing a aspect ratio */
gtk_widget_set_size_request(drawing_area, 600, 400);
gtk_container_add(GTK_CONTAINER (window), drawing_area);
gtk_widget_show(drawing_area);
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
/* and the window */
gtk_widget_show (window);
/* All GTK applications must have a gtk_main(). Control ends here
* and waits for an event to occur (like a key press or
* mouse event). */
gtk_main ();
return 0;
}
The main problem I see here is that you're not properly integrating your opencv code into the GTK event model.
GTK basically works with a message pump. Messages are sent in a queue, and GTK reads and unqueue them to react to those messages. In GTK 2, the expose-event event is emitted when a widget or portion of it needs to be drawn (in GTK 3, the draw event is used). You're suposed to connect a callback to that event to catch the event. Then in your callback, you draw a single frame, and then give the control back to GTK. It will call your callback again when it needs the next frame.
The problem here is that you never give the hand back to GTK, as your opencv code is enclosed in an infinite while(1) loop. You should instead just draw a single frame, and return.
The key event logic should also be handled using GTK, and not in your expose-event callback. Just call gtk_main_quit once you have seen the keystroke you're waiting for.
EDIT:
Once you can display one frame, you have to display them all. Call gtk_widget_queue_draw to tell GTK that the widget needs to be redrawn.
Once this is done, you'll see that you need some way of calling gtk_widget_queue_draw periodically. This is easilly done with GLib functions like g_timeout_add or g_idle_add. These functions tell the main event loop (what I called "message pump" above") to call a callback after a determined amount of time (for g_timeout_add) or just when there is no other events to process (for g_idle_add). Call gtk_widget_queue_draw in that callback and you're done.
Be aware that g_timeout_add doesn't allow to have a perfect timing, so the time between each frame may be too different from one frame to another. You may avoid this by augmenting the priority passed to g_timeout_add. You may also use a GTimer to compute in your timeout callback the time elapsed between the last frame and the current time, and deduce time remaining until your next frame. Then call g_timeout_add with that more accurate time. Don't forget to return FALSE instead of TRUE at the end of the timeout callback if you use the GTimer trick, otherwise you'll have n timeout callbacks running at frame n.

How to return a value from a function called using gtk callback?

I am a beginner in gtk and C gui programming and have two specific questions while imlementing a GUI for my C application.
I have called a function via a callback in my code and the function is supposed to return a value. How to get the value in my main from the function?
What is the best way to implement many function calls either from main or nested function calls in GUI using GTK. Should i design and open new window at each function call and if that is the case then how do i close it when its job is over or do i have some way wherein i can change the content of the same window across function calls after some I/O by the functions.
Sample code where i want function hello to return a value 144 after called by callback in main.
#include <gtk/gtk.h>
static gboolean delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
g_print ("delete event occurred\n");
return FALSE;
}
int hello(GtkWidget *widget, gpointer data)
{
int a=144;
return a;
}
/* Another callback */
static void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
int value;
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked",
G_CALLBACK (hello), NULL);
// printf("value is %d",value);
gtk_container_add (GTK_CONTAINER (window), button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main ();
return 0;
}
In your main:
int value = 0;
g_signal_connect (button, "clicked", G_CALLBACK (hello), &value);
You also must respect a signal's callback prototype. In your code, you made it return an int... For the GtkButton::clicked signal, this is:
void user_function (GtkButton *button, gpointer user_data)
Then, to return your value, just modify the variable from inside the callback:
int hello (GtkWidget *widget, gpointer data)
{
int *a = data;
*a = 144;
}
If you need to return several values, use a struct instead of an int.
Your second question is very unclear to me, so I can't answer to it.
One way to pass values back from a callback would be to give a pointer to some storage to g_signal_connect(). That pointer will then be passed to your handler, which can write its "return value" there. You could also pass the address of another function (or the address of a struct containing both data and function pointer, or whatever) to enable more complex behaviors in your handler function.
As for your second question, I don't think I understand it, and anyway each question should be its own post here.
As others have said, if you need to get data out of a callback then you need to pass in a pointer and set the value at that location, because you can't return.
This makes sense if you think about what is actually happening. When you are setting the callback when you call g_signal_callback() you are not actually calling your callback, you are just passing a pointer to your function, which GTK is then storing internally for later use.
Once you call gtk_main() you turn control of your program over to the gtk main loop. There, when signals are received the gtk main loop will call into your functions, but you have no control over what is happening inside the gtk main loop, it's not expecting a return value from your function, and if you could return something, you'd have no way of telling gtk what to do with it.

Resources