In the following example, compiled with GTK3, GtkExpander collapses unintendedly when I click in the entry field.
#include <gtk/gtk.h>
static void destroy (GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
gtk_init (&argc, &argv);
GtkWidget *entry;
entry = gtk_entry_new ();
GtkWidget *expander;
expander = gtk_expander_new ("test");
gtk_expander_set_expanded (GTK_EXPANDER(expander), TRUE);
gtk_container_add (GTK_CONTAINER(expander), entry);
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_add (GTK_CONTAINER(window), expander);
g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
However, GtkExpander does not collapse if it is expanded after gtk_widget_show_all(), i.e.:
gtk_widget_show_all (window);
gtk_expander_set_expanded (GTK_EXPANDER(expander), TRUE);
What's wrong with expanding the widget before gtk_widget_show_all()?
This was a bug in GTK+ which is fixed now.
For details see:
https://bugzilla.gnome.org/show_bug.cgi?id=783145
https://bugzilla.gnome.org/show_bug.cgi?id=774134
Related
I am receiving this error and not sure why...Please take a look at my buttons array, maybe I messed smth there, I am not sure...
The error i get is: Xlib: extension "RANDR" missing on display ":24.0".
and nothing happens after that, meaning my program doesnt run at all....
#include <gtk/gtk.h>
/* Our new improved callback. The data passed to this function
* is printed to stdout. */
static void callback (GtkWidget *widget, gpointer data)
{
system ((gchar *) data);
}
/* another callback */
static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
return FALSE;
}
int main (int argc, char *argv[])
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *box1;
/* 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 */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* This is a new call, which just sets the title of our
* new window to "My Assignments" */
gtk_window_set_title (GTK_WINDOW (window), "My Assignments");
/* Here we just set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 50);
/* We create a box to pack widgets into. This is described in detail
* in the "packing" section. The box is not really visible, it
* is just used as a tool to arrange widgets. */
box1 = gtk_vbox_new (FALSE,0);
/* Put the box into the main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/*array is here*/
GtkWidget *button[2];
int i;
for (i=0; i<2; i++)
{
button[i]=gtk_button_new();
}
button[0] = gtk_button_new_with_label ("Run shellscript");
g_signal_connect (button[0], "clicked",
G_CALLBACK (callback), "shellscript");
gtk_box_pack_start (GTK_BOX (box1), button[0], TRUE, TRUE, 0);
gtk_widget_show(button[0]);
button[1] = gtk_button_new_with_label ("Run program2 ");
g_signal_connect (button[1], "clicked",
G_CALLBACK (callback), "program");
gtk_box_pack_start (GTK_BOX (box1), button[1], TRUE, TRUE, 0);
gtk_widget_show(button[1]);
gtk_widget_show (box1);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
I am trying to change the cursor of a window dynamically with GTK3 but gtk_widget_get_parent_window doesn't seem to work.
Could someone please point out what I'm doing wrong? Thanks!
// https://developer.gnome.org/gtk3/stable/gtk-getting-started.html
// minimal example
#include <gtk/gtk.h>
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
// Here \/\/\/\/\/ .
GdkWindow* w = gtk_widget_get_parent_window(window);
GdkCursor* c = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_WATCH);
gdk_window_set_cursor(w, c);
// /\/\/\/\/\ .
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;
}
(main.exe:16508): Gdk-CRITICAL **: gdk_window_set_cursor: assertion
'GDK_IS_WINDOW (window)' failed
I am using GTK 3.16 with msys2
Many thanks in advance.
Extending #andlabs comment
Any attempt to change the cursor needs to be done after the widget has been added to the widget hierarchy or in GTK terms realized.
Calling gtk_widget_get_parent_window() or even gtk_widget_get_window() before a realize event has been fired for the widget will result in a NULL pointers in both cases.
Like #andlabs it is safer to use gtk_widget_get_window() in combination with a GtkWindow.
The solution.
static GdkWindow* G_WINDOW = 0;
static GdkCursor* G_CURSOR = 0;
// call after WindowRealize()
void changecursor()
{
assert(G_WINDOW != NULL);
gdk_window_set_cursor(G_WINDOW, G_CURSOR);
}
static void WindowRealize(GtkWidget *window, gpointer data)
{
G_CURSOR_HAND = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_HAND2);
G_WINDOW = gtk_widget_get_window(window);
}
static void activate(GtkApplication* app,gpointer user_data)
{
GtkWidget *window = gtk_application_window_new(app);
...
g_signal_connect(window, "realize", G_CALLBACK(WindowRealize), NULL);
gtk_widget_show_all (window);
}
utter total 100% coding noob here. I am experimenting in GTK+ and C and I'm trying to create a basic window which has an image over it.
This is my (probably cringeworthy) code:
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button;
GtkImage *image;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GtkButton");
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
image = gtk_image_new();
gtk_image_set_from_file(GTK_IMAGE(image),"/home/testbed/Downloads/efnbxw.jpg");
gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50);
gtk_widget_set_size_request(button, 80, 35);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
What did I do wrong?
Scrap the above code, it's just entirely incorrect
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window, *image;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
gtk_window_set_title(GTK_WINDOW(window), "Image");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(window), 2);
image = gtk_image_new_from_file("/home/testbed/Downloads/efnbxw.jpg");
gtk_container_add(GTK_CONTAINER(window), image);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
^^Heres my new code. It compiles and displayed a window with my selected image.
Can anyone here help me code this so that when the image is clicked, the application closes?
Image widgets are one of those that don't capture events (because they don't have their own window). You can place such widgets in an eventbox widget and enable the capture of events such as button presses. Try this modified version of your update.
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window, *image;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
gtk_window_set_title(GTK_WINDOW(window), "Image");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(window), 2);
image = gtk_image_new_from_file("/home/testbed/Downloads/efnbxw.jpg");
//gtk_container_add(GTK_CONTAINER(window), image);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget* eventBox = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(window), eventBox);
// Capture button presses.
gtk_widget_add_events (eventBox, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(eventBox), "button-press-event", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(eventBox), image);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Segmenation fault means that you are accesing memory positions that are out of the bounds defined in your program.From the above code i assume that one of your pointers causes the problem..
I have a main window with a menu wich opens another window. This secondary window has a button Close. That button has the signal clicked connected. My problem is that I don't know how to close/destroy that parent window. I have tried with gtk_widget_destroy, but an error appears because window is not a widget .... I haven't found any function to destroy the parent window ....
Can anyone show me the way, please?
Thanks in advance.
-----------------------------------------------
Ok. I post a piece of code. When I execute the program I click in "Open window" button. A new window is openned with one button "Close". If I click in "Close" button I get next error in terminal: (Windows:13801): Gtk-CRITICAL **: gtk_widget_destroy: assertion `GTK_IS_WIDGET (widget)' failed
The code is:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
void open_window(GtkWidget *widget, gpointer window);
void close_window(GtkWidget *widget, gpointer window);
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Windows");
gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
button = gtk_button_new_with_label("Open window");
gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50);
gtk_widget_set_size_request(button, 80, 35);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(open_window), G_OBJECT(window));
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
void open_window(GtkWidget *widget, gpointer window)
{
GtkBuilder *builder;
GtkWidget *secondWindow = NULL;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "secondWindow.glade", NULL);
secondWindow = GTK_WIDGET (gtk_builder_get_object (builder, "secondWindow"));
gtk_builder_connect_signals (builder, NULL);
g_object_unref (G_OBJECT (builder));
gtk_window_set_modal(GTK_WINDOW(secondWindow), TRUE);
gtk_widget_show_all(secondWindow);
}
void close_window(GtkWidget *widget, gpointer window)
{
gtk_widget_destroy(GTK_WIDGET(window));
}
In file "secondWindow.glade" is defined a window, a table and a button placed in the middle cell of the table. Also, it is defined a handle for the "clicked" event button named "close_window".
Link to glade file if anyone wants to execute it: https://sites.google.com/site/marvalsiteimages/secondWindow.glade
I hope this could help you to understand my problem.
Thansk.
-------------------------------------------------
Final code based on the response:
void open_window(GtkWidget *widget, gpointer window)
{
GtkBuilder *builder;
GtkWidget *secondWindow = NULL;
GtkWidget *closeButton = NULL;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "secondWindow.glade", NULL);
secondWindow = GTK_WIDGET (gtk_builder_get_object (builder, "secondWindow"));
closeButton = GTK_WIDGET (gtk_builder_get_object (builder, "closeWindowButton"));
g_signal_connect (G_OBJECT (closeButton),
"clicked",
G_CALLBACK (close_window),
G_OBJECT (secondWindow)); // here is the magic: the callback will get the window to close
g_object_unref (G_OBJECT (builder));
gtk_window_set_modal(GTK_WINDOW(secondWindow), TRUE);
gtk_widget_show_all(secondWindow);
}
Your problem is that the "clicked" signal of the button of the second window is connected from the glade file. But the signal handler needs a pointer to the window to destroy it. This is passed through the "user_data" parameter of the signal callback.
One way would be by passing the second window as the user_data argument in Glade (give a look at this Glade tutorial), but the argument is supposed to be a pointer, and I don't know how one can do it with glade. EDIT: just click on the user data field associated to this signal in glade, and a popup will allow you to select the object to pass to the signal handler. Just select your "secondWindow" object.
Another way to do it would be to just remove the signal handling from the glade file, and connect manually the clicked signal from code, passing a pointer to the second window as user data:
void open_window(GtkWidget *widget, gpointer window)
{
GtkBuilder *builder;
GtkWidget *secondWindow = NULL;
GtkWidget *closeButton = NULL;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "secondWindow.glade", NULL);
secondWindow = GTK_WIDGET (gtk_builder_get_object (builder, "secondWindow"));
closeButton = GTK_WIDGET (gtk_builder_get_object (builder, "closeWindowButton"));
g_signal_connect (G_OBJECT (closeButton),
"clicked",
G_CALLBACK (close_window),
G_OBJECT (secondWindow)); // here is the magic: the callback will get the window to close
g_object_unref (G_OBJECT (builder));
gtk_window_set_modal(GTK_WINDOW(secondWindow), TRUE);
gtk_widget_show_all(secondWindow);
}
I am developing an application that has a numeric keypad and a text box when clicked on a button, text box shows the number.
I need to write a function to each button? Or you can pass a text and a widget as parameter?
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
void callback( GtkWidget *widget,
gpointer data )
{
gtk_entry_append_text(entry, text);
}
void create_button(GtkWidget* table,GtkWidget* entry,
int start_r,int end_r,
int start_c,int end_c,
char* label)
{
GtkWidget *button;
button = gtk_button_new_with_label (label);
g_object_set_data( G_OBJECT( button ),
"char", (gpointer)label );
g_signal_connect (button, "clicked",
G_CALLBACK (callback), entry);
gtk_table_attach_defaults (GTK_TABLE(table), button, start_c, end_c, start_r, end_r);
gtk_widget_show (button);
}
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit ();
return(FALSE);
}
int main(int argc,char* argv[]){
GtkWidget *window;
//GtkWidget *button;
GtkWidget *table;
GtkWidget *entry;
//GtkWidget *label;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Armario");
g_signal_connect (GTK_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
table = gtk_table_new (2, 2, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
entry = gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(entry),10);
gtk_entry_set_placeholder_text(GTK_ENTRY(entry),"Teste");
gtk_table_attach_defaults (GTK_TABLE(table), entry, 0, 2, 1, 2);
gtk_widget_show(entry);
create_button(table,entry,0,1,0,1,"Botao");
gtk_widget_show (table);
gtk_widget_show (window);
gtk_main ();
return 0;
}
The answer to your question is yes, you can pass a widget in Gtk+ to a callback. Actually, the first parameter of the callback for the clicked signal is the button which received the signal (ie. usually the button that was clicked). As you can see in the sample code below, you can extract from the button its label and use it as text.
[...] /* In create_button... */
/* Make your buttons be notified when they are clicked */
g_signal_connect (button, "clicked", G_CALLBACK (on_button_clicked), entry);
[...]
/* Append the text in the button to the text entry */
void on_button_clicked (GtkButton *button, gpointer user_data)
{
GtkEntry *entry = user_data;
const gchar *text = gtk_button_get_label (button);
gint position = 0;
gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &position);
}
I'm using gtk_editable_insert_text because gtk_entry_append_text has been deprecated for a long time. Passing the "entry" parameter to the callback is possible by using the last parameter of g_signal_connect which allows you to specify some data that you need to access in your callback. This info is then made available to the callback in the "user_data" parameter.
Your exemple could also be improved by using gtk_widget_show_all, and I also don't see the point in calling g_object_set_data on the "char" property, as the text is already set in the label property (and retrieved with gtk_button_get_label).
Two options, that I can think of:
GTK widgets are really GObjects, so you can attach to them arbitrary pieces of data. See the functions g_object_set_data/g_object_set_data_full/g_object_get_data. So you can just add the text to the button as an attached data and retrieve it when needed.
You can pass any data you need to a callback by defining a struct with all the fields, and passing a pointer to it. If the struct cannot be declared statically, you can malloc it and use g_signal_connect_data to specify the function to release the data:
For example:
struct entry_and_text;
{
GtkWidget *w;
char *text;
};
void free_data(gpointer data, GClosure *closure)
{
free(data);
}
entry_and_text *data = (entry_and_text *)malloc(sizeof(entry_and_text));
data->w = entry;
data->text = label;
g_signal_connect_data (button, "clicked",
G_CALLBACK (callback), data, free_data, 0);