How do I intercept a gtk window close button click? - c

On on GTK window there is a red close icon rendered in the title bar. Normally when you click on this, the window is closed and it's resources released.
Is there a way of intercepting the normal flow to prevent the window from being destroyed so that I can show it again later? i.e. I want to hide the window not close/destroy it.
This is what I have so far.
void destroy_window_callback(GtkWidget* widget, WebWindow_Linux* source)
{
printf("Don't destroy the window, just hide it.\n");
}
g_signal_connect(web_window, "destroy", G_CALLBACK(destroy_window_callback), this);

This is probably what you need
#include <gtk/gtk.h>
void
on_button_clicked(GtkButton *button, gpointer data)
{
GtkWidget *widget;
widget = (GtkWidget *) data;
if (widget == NULL)
return;
gtk_widget_show(widget);
return;
}
gboolean
on_widget_deleted(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_widget_hide(widget);
return TRUE;
}
int
main(int argc, char **argv)
{
GtkWidget *window1;
GtkWidget *window2;
GtkWidget *button;
gtk_init(&argc, &argv);
window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("Show again...");
g_signal_connect(G_OBJECT(window1),
"destroy", gtk_main_quit, NULL);
g_signal_connect(G_OBJECT(window2),
"delete-event", G_CALLBACK(on_widget_deleted), NULL);
g_signal_connect(G_OBJECT(button),
"clicked", G_CALLBACK(on_button_clicked), window2);
gtk_container_add(GTK_CONTAINER(window1), button);
gtk_widget_set_size_request(window1, 300, 100);
gtk_widget_set_size_request(window2, 300, 100);
gtk_widget_show_all(window1);
gtk_widget_show(window2);
gtk_main();
return 0;
}
We basically have three widgets, two top level windows and a button. The first window has it's "destroy" event connected to gtk_main_quit() quitting the application when the window's close button is pressed. The second window has it's "delete-event" connected to a custom function. This is the important one. As you see it returns TRUE indicating that the signal was handled and thus preventing to call the default handler and hence preventing the call to gtk_widget_destroy(). Also in it we can hide the widget if we want.

Related

How can I configure a GtkWidget signal that runs every time a widget is shown?

The show signal seems to only be called the first time a widget is shown. If I call gtk_widget_show on the widget in question, if it has already been shown, any functions passed to g_signal_connect to the widget in question with the show signal will not be called. I attempted to use the show signal for a button whose text is determined by an external state that the button changes, so when the button first becomes visible it successfully shows the initial state, but even though I change the state in the button handler then call gtk_widget_show, the text is not updated when the button is clicked. How can I configure a widget to run on EVERY show event, not just the first.
Requirement:
update button label based on state
state change happen on button click
One solution could be to update the status when the button is clicked, and then set the button's label, e.g. like this:
update_state();
gtk_button_set_label(button, state);
If more parts of the user interface than just the button should be updated, one could think about introducing a separate function updateUI.
A small demo could look like this:
#include <gtk/gtk.h>
static int cnt;
static char state[16];
static void update_state() {
snprintf(state, sizeof(state), "clicked %d", cnt++);
}
static void button_show(__unused GtkWidget *widget, __unused gpointer data) {
g_print("show\n");
}
static void button_clicked(GtkButton *button, __unused gpointer data) {
g_print("clicked\n");
update_state();
gtk_button_set_label(button, state);
}
static void buildUI(GApplication *app, __unused gpointer data) {
GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app));
gtk_window_set_title(GTK_WINDOW(window), "GtkButton");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
GtkWidget *button = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button), state);
gtk_widget_set_size_request(button, 80, 32);
gtk_widget_set_halign(button, GTK_ALIGN_START);
gtk_widget_set_valign(button, GTK_ALIGN_START);
gtk_container_add(GTK_CONTAINER(window), button);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(button_clicked), NULL);
g_signal_connect(G_OBJECT(button), "show",
G_CALLBACK(button_show), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
}
int main(int argc, char *argv[]) {
GtkApplication *app = gtk_application_new("com.example.MyApp", G_APPLICATION_FLAGS_NONE);
update_state();
g_signal_connect(app, "activate", G_CALLBACK(buildUI), NULL);
g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return 0;
}
It updates the label whenever the button is clicked.

Should I use a global variable in gtk callback functions? [duplicate]

This question already has answers here:
Passing additional arguments to gtk function
(3 answers)
GTK passing structure to callback function in C
(1 answer)
Closed 3 years ago.
Hi I'm trying to program with GTK+ 2 and when I need to create a popup window after the "clicked' signal of a button, I use " gtk_widget_set_sensitive(button, FALSE) " so as not to be able to launch another popoup window from the same button when one is already launched. Yet the only way to close the popup with another callback function containing " gtk_widget_destroy(popup) " also means this callback can't "see" the first button to turn it sensitive again. Should I use a global variable and asign the popup window to it so my second callback function will see it? Or do I define more global widgets ?
What I'm really getting at is using global variables in something like GTK a common thing to do?, such as in header files, or is it bad practice at all?
Here is a sample program (with less stuff in the first callback than normal!)
#include <gtk/gtk.h>
// Is it good to set a temporary global GtkWidget * so I can asign it to
// button1 later and then use this temporary variable to set the widget sensitive again.
// GtkWidget * temp;
static void popup_win(GtkWidget *, gpointer data);
static void close_up(GtkWidget *, GtkWidget *);
int main(int argc, char * argv[])
{
GtkWidget * window, * button1, * vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "EXAMPLE PROGRAM");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_widget_set_size_request(window, 800, 300);
button1 = gtk_button_new_with_label("Click here");
g_signal_connect(G_OBJECT(button1), "clicked",
G_CALLBACK(popup_win), NULL);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), button1, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static void popup_win(GtkWidget * btn, gpointer data)
{
gtk_widget_set_sensitive(btn, FALSE);
// I could use temp here. Then get to it in close_up function.
// temp = btn
GtkWidget * window2, * button2, * hbox;
window2 = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_set_title(GTK_WINDOW(window2), "POPUP WINDOW");
gtk_container_set_border_width(GTK_CONTAINER(window2), 10);
gtk_widget_set_size_request(window2, 100, 200);
button2 = gtk_button_new_with_label("Click me too");
g_signal_connect(G_OBJECT(button2), "clicked",
G_CALLBACK(close_up), (gpointer) window2);
hbox = gtk_hbox_new(TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button2, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window2), hbox);
gtk_widget_show_all(window2);
}
static void close_up(GtkWidget * btn, GtkWidget * win)
{
// can't get at button1 so I can't set widget sensitve again.
// gtk_widget_set_sensitive(button1, TRUE);
// Unless I'm using temp variable.
// gtk_widget_set_sensitive(temp, TRUE);
gtk_widget_destroy(win);
}```

Set frame position of decorated GtkWindow on screen

I have a task to restore window frame position on screen on program startup - so to define initial window position.
Consider the following decorated GtkWindow instance on Linux:
The window has two principal boxes: frame box and client box.
And there are two GTK functions that allow to set size and position of the window on screen:
gtk_window_move() - sets window's frame box position on screen and
gtk_window_resize - sets window's client box size.
Question:
Is there any way in GTK to define initial frame placement of the window?
On Windows I can do that by calling MoveWindow() and on MacOS NSWindow setFrame method. But on GTK... Am I asking too much?
Connect to the "realize" signal for the window (important: before calling gtk_widget_show). Then call gtk_window_move from the handler:
#include <gtk/gtk.h>
void on_window_realize(GtkWidget *widget,
gpointer user_data)
{
GtkWindow *window = GTK_WINDOW(user_data);
gtk_window_move(window, 100, 40);
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window,
"realize",
G_CALLBACK(on_window_realize),
(gpointer)window);
g_signal_connect(window, "destroy", gtk_main_quit, NULL);
gtk_widget_show(window);
gtk_main();
return 0;
}

How to center a dialog window on the main window in GTK?

I want to print small warning messages. To achieve that, I'm creating a new window and I want it to be centered on the main window. So far I've tried setting its parent with gtk_widget_set_parent, using GTK_WINDOW_POPUP and GTK_WINDOW_TOPLEVEL but nothing worked.
How to center the window on the main window?
Here's the code for the function:
static void pop_warning(char *title, char *text)
{
GtkWidget *warning_window;
GtkWidget *box;
GtkWidget *label;
GtkWidget *button;
warning_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(warning_window), title);
g_signal_connect(GTK_WINDOW(warning_window), "destroy", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(warning_window), 20);
gtk_window_set_resizable(GTK_WINDOW(warning_window), FALSE);
//window is the main window
gtk_widget_set_parent(warning_window, window);
gtk_window_set_position(GTK_WINDOW(warning_window), GTK_WIN_POS_CENTER_ON_PARENT);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_container_add(GTK_CONTAINER(warning_window), box);
label = gtk_label_new(text);
gtk_box_pack_start(GTK_BOX(box), label, TRUE, FALSE, 0);
button = gtk_button_new_with_label("Ok");
g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), warning_window);
gtk_box_pack_start(GTK_BOX(box), button, TRUE, FALSE, 0);
gtk_widget_show_all(warning_window);
}
gtk_window_set_position(GTK_WINDOW(warning_window), GTK_WIN_POS_CENTER_ON_PARENT);
only works if you first call
gtk_window_set_transient_for(GtkWindow *window, GtkWindow *parent);
as mentioned explicitly in the documentation.
You could also try to use GTK_WIN_POS_CENTER_ALWAYS that has not the above mentioned constrain - at least not according the docs.

Splash Screen in GTK

I'm new to GTK and i'm using it to create UI in C. I've created a splash screen and i'm able to close it after specified seconds using the function g_timeout_add(100, function_to_call, NULL);. The Splash screen works great. but the problem is when in extend my program further (i.e) After closing the splash screen I want another window to be displayed automatically, it doesn't happen so. Both the windows open together. Here is my program.
gboolean function_to_call(gpointer data){
gtk_quit_main();
return(FALSE);
}
int main (int argc, char *argv[]){
GtkWidget *window, *image, *another_window;
gtk_init(&argc, &argv);
.
.
.
.
.
.
.
g_timeout_add (100, function_to_call, NULL);
gtk_main ();
/*if my program is till this, splash screen closes after 1 sec . But when i try
*to define another window from here onwards and call gtk_widget_show() and gtk_main()
*again for another_ window, window and another_window both open together and window
*doesn't close after 1 sec. */
}
Any kind of help is appreciatable.
Thank you.
Your function_to_call doesn't close your splash window here, it ends the gtk_main event loop. You don't need to end the event loop.
What you want to do instead, in your function_to_call, is hide (or destroy) your splash window and show your next window (gtk_widget_hide(),gtk_widget_show()).
I've created a splashscreen header file which is shown below..
#include <gtk/gtk.h>
/* Close the splash screen */
gboolean close_screen(gpointer data)
{
gtk_widget_destroy((GtkWidget*)data);
gtk_main_quit ();
return(FALSE);
}
int Show_Splash_Screen(char* image_name,int time,int width,int height)
{
GtkWidget *image, *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (window, width, height);
gtk_window_set_decorated(GTK_WINDOW (window), FALSE);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
image=gtk_image_new_from_file(image_name);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all (window);
g_timeout_add (time, close_screen, window);
gtk_main ();
return 0;
}
just include this file and to show a splash screen call the function
Show_Splash_Screen("image_path",time_in_seconds,width_of_image_in_pixels,height_of_image_in_pixels);

Resources