InfoBar only shown on window change - c

Why is the GtkInfoBar only visible if I change the window (focus)?
Hit the F5 key to get the InfoBar visible. Close the InfoBar and hit F5 again.
On my debian 8 (Gnome 3.20) system the InfoBar is only visible the first time, from the second time on it's only visible if I change the focus of the application window.
// gcc `pkg-config --cflags gtk+-3.0` -o info_bar infobar_nonglade.c `pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
// Callback to close the window with Esc key
static gboolean check_escape(GtkWidget *widget, GdkEventKey *event, gpointer data) {
if (event->keyval == GDK_KEY_Escape) {
gtk_main_quit();
return TRUE;
}
return FALSE;
}
static gboolean on_key_f5(GtkWidget *widget, GdkEventKey *event, gpointer infobar) {
if (event->keyval == GDK_KEY_F5) {
gtk_widget_set_visible(infobar, !(gtk_widget_get_visible(infobar)));
return TRUE;
}
return FALSE;
}
int main (int argc, char **argv) {
gtk_init(&argc, &argv);
GtkWidget *button, *content_area, *infobar, *message_label, *vbox, *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
infobar = gtk_info_bar_new();
button = gtk_button_new_with_label ("OK");
gtk_window_set_default_size (GTK_WINDOW (window), 1024, 600);
gtk_widget_set_no_show_all (infobar, TRUE);
gtk_info_bar_add_button (GTK_INFO_BAR (infobar),
"OK",
GTK_RESPONSE_OK);
g_signal_connect (infobar, "response", G_CALLBACK (gtk_widget_hide), NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_box_pack_start (GTK_BOX (vbox), infobar, FALSE, FALSE, 0);
gtk_widget_show_all (vbox);
// Connect callback to close the window with the Esc key
g_signal_connect (window, "key_press_event", G_CALLBACK (check_escape), NULL);
g_signal_connect (window, "key_press_event", G_CALLBACK (on_key_f5), infobar);
gtk_widget_show_all (window);
gtk_main();
return 0;
}

I can not test it on my machine, but you can try:
gtk_widget_set_visible(infobar, !(gtk_widget_get_visible(infobar)));
instead of
gtk_widget_set_no_show_all (infobar, FALSE);
gtk_widget_show_all (infobar);
Also, why are you invalidating the event returning TRUE on gboolean on_key_f5?

This looks like an old well known bug :(
Simple solution is to disable animations. I can live with that perfectly fine.
int main (int argc, char **argv) {
gtk_init(&argc, &argv);
// Fix InfoBar Bug: https://bugzilla.gnome.org/show_bug.cgi?id=710888
g_object_set (gtk_settings_get_default (), "gtk-enable-animations", FALSE, NULL);
...
}

Related

Java Swing "pack" - GTK Equivalent

I have for example this code:
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), 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);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("foo.bar", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
It looks like this:
How can I automatically resize the window, so it has the perfect size for the one button.
With Java Swing, you could simply call pack(), but I wasn't able to find a similar method for GTK.
For GtkWindow there would be gtk_window_resize, but it requires giving an height and width, so I would have to calculate it manually.
This would work with just one button, but anything more complex would be error-prone and prone to failure.
Is there any equivalent to pack?

Ignore keyboard cursor in GTK3 C

Using GTK3 in C, I have an interface with buttons. I want a user with a mouse to be able to press a button OR use press a single button on the keyboard to do the same thing.
MWE (modified from GTK3 Hello World example):
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
In this program, the user can press the left arrow key to execute thing. The user can also click on the gui button to execute thing. However, hitting certain keyboard keys such as space or enter will "click" on the gui button to execute thing.
How do I prevent the keyboard from "clicking" on a button which the keyboard cursor is on in this case?
Fake Button Hack
I have hacked a workaround into my code for now using a useless button. I will not be marking this answer as solved since it is very sloppy, but it does the job until something better becomes available.
Description
This hack adds another button with no functions assigned. Using gtk_widget_grab_focus, we force this useless "fakebutton" to hold keyboard focus. We reissue this command every time a button is pressed.
Problems
Grabbing focus back to the fakebutton is slow. The user can issue a quick succession of commands (in the case of the MWE by pressing Left and Space to erroneously issue the otherthing function).
MWE
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
GtkWidget *fakebutton;
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
gtk_widget_grab_focus(fakebutton);
} else {
gtk_widget_grab_focus(fakebutton);
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
fakebutton = gtk_button_new();
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), fakebutton);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}

How to print a continuous message while mouse button pressed (g_timeout_add)?

I have this code:
#include <stdio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
guint threadID = 0;
guint serial_counter = 0;
static gboolean
serial_data (gpointer user_data)
{
printf("hello\n");
printf("counter: %d\n", serial_counter);
serial_counter++;
return user_data;
}
static void
on_pressed (GtkButton* button, gpointer user_data)
{
if (user_data == 1)
{
threadID = g_timeout_add(250, serial_data, user_data);
}
else if (user_data == 0)
{
g_source_remove(threadID);
threadID = 0;
}
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
GtkWidget *stop_button;
GtkWidget *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "test.c");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
stop_button = gtk_button_new_with_label (_("Stop"));
gtk_box_pack_start (GTK_BOX (box), stop_button, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box);
g_signal_connect (window, "button-press-event", G_CALLBACK (on_pressed), 1);
g_signal_connect (stop_button, "clicked", G_CALLBACK (on_pressed), 0);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
Which can be compiled by using:
gcc prueba.c `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0` -o test
I want to print a message only when the button of the mouse is pressed (clicked but not released). Can this be achieved by modifying this code?
The objective is to press the right button of the mouse in any part of the current window and get a message printed, until the button is released.
I have no idea where you got the declaration of your signal handler function. It should look different according to GTK manual
This is some stripped example where I use "pressed" and "released" events to indicate button state and depending on the state I handle "mouse moved" events accordingly.
For your purpose you can add the print function and the timer.
static gboolean on_mouse_button_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
if (event->button.button != 3) // right button
return FALSE;
if (event->button.type == GDK_BUTTON_PRESS)
{
if (!button_pressed)
{
button_pressed = TRUE;
// Start timer
}
}
else if (event->button.type == GDK_BUTTON_RELEASE)
{
if (button_pressed)
{
button_pressed = FALSE;
// Stop timer
}
}
return TRUE;
}
...
g_signal_connect(G_OBJECT(widget), "button-press-event", G_CALLBACK(on_mouse_button_event), NULL);
g_signal_connect(G_OBJECT(widget), "button-release-event", G_CALLBACK(on_mouse_button_event), NULL);

Printing value of entry box in a dialog in gtk c

I have worked recently with gtk+ in c language.
I have tried to communicate between two callbacks in a dialog and not in the main window (like here). But, unlike the solutions in the link, the program crushes (in the second callback when I try to use the widget I get from the parameters).
This is my code for This:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>
static void print_text (GtkWidget *widget, gpointer data)
{
GtkEntry* entry = data;
printf("%s", gtk_entry_get_text(entry));
}
static void open_dialog (GtkWidget *widget, gpointer data)
{
GtkWidget *window = data;
GtkWidget *dialog;
GtkWidget *content_area;
GtkWidget *grid;
GtkWidget *label;
GtkWidget *button;
static GtkEntry *textbox;
dialog = gtk_dialog_new_with_buttons ("Get Text",
window,
GTK_DIALOG_MODAL,
GTK_STOCK_OK,
GTK_RESPONSE_OK,
NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
grid = gtk_grid_new();
gtk_container_add (GTK_CONTAINER (content_area), grid);
label = gtk_label_new("Value: ");
gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
textbox = gtk_entry_new();
gtk_entry_set_text(textbox, "<Value>");
gtk_grid_attach(GTK_GRID(grid), textbox, 1, 0, 1, 1);
gtk_widget_show_all (dialog);
g_signal_connect (GTK_DIALOG (dialog), "response", G_CALLBACK (print_text), textbox);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *entry;
GtkWidget *grid;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Print Text");
g_signal_connect (button, "clicked", G_CALLBACK (open_dialog), window);
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1);
gtk_widget_show_all (window);
}
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
The program should have printed the value of the entry box which in the dialog after closing the dialog. Note: in the main window there is a button that opens the dialog.
Thanks for helping!
Problem is on the print_text function. The prototype for GtkDialog response signal is:
void user_function (GtkDialog *dialog,
gint response_id,
gpointer user_data)
So you must change your function to:
static void print_text (GtkWidget *widget, gint response_id, gpointer data)
{
GtkEntry* entry = data;
printf("%s", gtk_entry_get_text(entry));
gtk_widget_destroy (widget); // This will close the dialog
}

How to switch between windows in GTK3 (C Language)

I have an App which as some point Opens a new Window and works fine.
Then After I'm done with it, I need to switch back to the main window.
I understood that I need the function:
gtk_widget_hide();
but I cant figure out how to hide the main Window, to print only the second one and again after I click the button in the second window to go back to the first one.
This is what I have so far:
#include <stdio.h>
#include <gtk/gtk.h>
static void crete_new_wind (GtkWidget *widget);
gboolean destroy (GtkWidget *window);
int main (int argc, char *argv[]){
GtkWidget *window, *button, *box;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "First Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Go to Window B");
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (crete_new_wind), (gpointer) window);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void crete_new_wind (GtkWidget *widget){
GtkWidget *window, *button, *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Second Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);;
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), widget);
button = gtk_button_new_with_label ("Go back to Window A");
g_signal_connect (G_OBJECT (button), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_hide(widget);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
}
gboolean destroy (GtkWidget *widget){
gtk_widget_destroy (widget);
return TRUE;
}
If I click on the button(Go to Window B) I have this:
But the main window is still there, avaible to the user which is not what I need.
Thats because the clicked callback wants two parameters
Change the prototype and the function to
static void crete_new_wind(GtkButton *dummy, gpointer widget);
static void crete_new_wind(GtkButton *dummy, gpointer widget) {
in order to use the second parameter in your function.

Resources