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.
Related
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.
I am trying to create an application in which I need to draw on a transparent window which stays above all other windows and invisible to the window manager, hence trying to set the override redirect of a window to true .But setting the override redirect for a GdkWindow causes segmentation fault.
#include <gtk/gtk.h>
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("com.github.application.name",
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;
}
compiling with gcc using
gcc -o out main.c `pkg-config --cflags --libs gtk+-3.0`
what am I missing here? any help is appreciated. Thanks.
gtk_widget_get_window() can return NULL. The reason your code is segfaulting is probably because you're calling gdk_window_set_override_redirect() on a NULL pointer.
For the underlying reason why gtk_widget_get_window() can return NULL: a GdkWindow maps to the concept of a surface; in X11 this is called an XWindow, hence the name. To let the compositor show your surface/XWindow, you have to explicitly map it.
GTK does the mapping operation the moment the GtkWindow widget is told to show itself (ie when you call gtk_window_present() or gtk_widget_show()). Once it actually associates with an underlying GdkWindow, it will emit the "realize" signal to which you can connect to .
So, in other words, you can either:
Call gdk_window_set_override_redirect(); after showing the window
Connect to the "realize" signal of your window variable, and call gdk_window_set_override_redirect(); inside the callback
Your code fails because gdk_window is NULL.
You can ask the window to be created with gtk_window_present:
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gtk_window_present(GTK_WINDOW(window));
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}
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.
The following program always works OK — shows the menu with one item — if launched from the terminal, but not if launched by the i3 window manager directly (when bound to a key).
In the latter case, most of the time it does print “Entering gtk main loop.”, but then simply does not get shdown; though approximately once per 20 key presses it does get shown!
Why?
#include <gtk/gtk.h>
#include <stdio.h>
static
void
deactivate_handler(GtkMenuShell *instance, gpointer user_data)
{
(void) instance; (void) user_data; // unused parameters
gtk_main_quit();
}
int
main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *menu = gtk_menu_new();
GtkWidget *item = gtk_menu_item_new_with_label("Test");
gtk_menu_attach(GTK_MENU(menu), item, 0, 1, 0, 1);
g_signal_connect(menu, "deactivate", G_CALLBACK(deactivate_handler), NULL);
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
fprintf(stderr, "Entering gtk main loop.\n");
gtk_main();
return 0;
}
I suspect calling gtk_menu_popup before gtk_main will lead to weird behavior. You're not changing data, like gtk_widget_show_all that changes a flag, you're actually trying to do actions.
One trick I see is switching to GtkApplication and run gtk_menu_popup in response to the GtkApplication's activate signal. At that time you're already in the main loop.
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.