Placing images in a fixed layout GTK2 - c

I have an application that is attempting to do the following:
Create a GTK2 top level main window
Add a fixed frame into the main window for absolute positioning of widgets
Create a matrix of GtkImages that will be used to display animated GIFS and static JPEGS
On start-up the static JPEGS picked randomly from a list will fill the matrix
When an event happens the matrix will be filled with animated GIFS
When the animation is over possibly different JPEGS will again be displayed in the matrix
Run time errors are happening only when two or more of the randomly selected JPEGS are placed in a row of the matrix.
Here is an example of such a run time error:
(wrong:3909): Gtk-WARNING **: Can't set a parent on widget which has a parent
If each image of the row are unique no run time errors occur.
Code snippets and run time output are as follows:
/*
* Compile me with:
* gcc -Wall -o wrong wrong.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
*/
/* header includes */
/**** prototypes ****/
/********************/
typedef struct
{
unsigned int pixel_width, pixel_height;
gchar fileName[20];
GtkWidget *image;
}symbol_t;
symbol_t symbols[] =
{
{ 118, 107, "images/LO.jpg", NULL },
{ 118, 107, "images/L1.jpg", NULL },
{ 118, 107, "images/L2.jpg", NULL },
{ 118, 107, "images/L3.jpg", NULL },
{ 118, 107, "images/H1.jpg", NULL },
{ 118, 107, "images/H2.jpg", NULL },
{ 118, 107, "images/H3.jpg", NULL },
{ 118, 107, "images/H4.jpg", NULL },
{ 118, 107, "images/H5.jpg", NULL }
};
GtkWidget *frame; /* for absolute positioning of widgets */
GtkWidget *window;
int Init( void )
{
/* initialize random number generator */
}
static void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
/* setup top-level window setting the background to the image contained
in *filename and return window widget
*/
return(window);
}
int main (int argc, char *argv[])
{
unsigned int y, i, pos_x, pos_y;
gtk_init (&argc, &argv);
Init(); // init random number generator
window = SetupWindow("Broken", "images/background.jpg");
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
frame = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), frame);
/* setup symbol jpgs */
for( i = 0; i < 9; i++ )
{
/* load each symbol image into memory */
symbols[i].image = gtk_image_new_from_file( symbols[i].fileName );
}
/* display some symbols */
pos_y = 150;
pos_x = 187;
for( y = 0; y < 5 ; y++ ) /* first row - 5 symbols */
{
i = (unsigned int)(random()%9);
printf("Symbol[%d] [%s]\n", i, symbols[i].fileName);
gtk_fixed_put(GTK_FIXED(frame), symbols[i].image, pos_x, pos_y);
pos_x += symbols[i].pixel_width;
}
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
Run time errors when two or more matching symbols ( images ) are placed on the row:
[chim] ~/source/matrix > ./wrong
Symbol[1] [images/L1.jpg]
Symbol[7] [images/H4.jpg]
Symbol[0] [images/LO.jpg]
Symbol[7] [images/H4.jpg]
(wrong:3909): Gtk-WARNING **: Can't set a parent on widget which has a parent
Symbol[5] [images/H2.jpg]
(wrong:3909): Gtk-CRITICAL **: gtk_widget_destroy: assertion `GTK_IS_WIDGET (widget)' failed
(wrong:3909): Gtk-CRITICAL **: gtk_widget_destroy: assertion `GTK_IS_WIDGET (widget)' failed
When this occurs some of the images in the row are empty ( white ).
Output when no matching symbols ( images ) are placed on the row:
[chim] ~/source/matrix > ./wrong
Symbol[1] [images/L1.jpg]
Symbol[6] [images/H3.jpg]
Symbol[3] [images/L3.jpg]
Symbol[0] [images/LO.jpg]
Symbol[4] [images/H1.jpg]
And in this case all images are displayed properly.
Any suggestions about how to fix and what I might be doing wrong?

Once you place the image into another widget, it becomes owned and managed by that (parent) widget -- you can't add it to more than one widget.
The simple way to get this to work is to load the image with gtk_image_new_from_file() each time you want to add it to the window. If you don't want to do that, maybe you can use something like gtk_image_new_from_image() to copy the image prior to adding it to the widget.

Related

Rezie gtk3 window to fit grid

On the first call of
gtk_main();
The size of the window is set by the total size of the grid.
But on second calls, it doesn't update.
Code to replicate
int main(int argc, char **argv) {
GtkWidget *mainWidget, *grid, *calculate;
gtk_init(&argc, &argv);
mainWidget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
grid = gtk_grid_new();
gtk_container_add(GTK_CONTAINER(mainWidget), grid);
int i;
static GtkWidget *a[10];
for (i = 0; i != 10; i++) {
char str[1];
a[i] = gtk_button_new_with_label(str);
gtk_grid_attach(GTK_GRID(grid), a[i], 1, i, 1, 1);
g_signal_connect(a[i], "clicked", G_CALLBACK(gtk_main_quit), NULL);
}
gtk_window_set_decorated(mainWidget, FALSE);
gtk_widget_show_all(mainWidget);
gtk_main();
for (i = 0; i != 9; i++) {
gtk_container_remove(GTK_GRID(grid), a[i]);
}
gtk_widget_show_all(mainWidget);
gtk_main();
return 0;
}
Well. I tried to use GDB to find the function that calculates the size of the window on the first call but I'm having some trouble.
So, as it turns out, unlike other toolkits. Not naming names (QT, Most Web Browsers), you (by default) cannot shrink a GTK window below its contents. So, a practical solution to this problem is.
gtk_window_resize(mainWidget, 1, 1)

Simulate backspace button press gtk in C

I am writing an app on raspberry in gtk+3/C which requires a virtual numpad (e.g 0-9, backspace and enter). I will use it with a touch screen, so no keyboard or mouse available (just like a kiosk).
I am adopting this code which allows me to use button press to emulate the number and display to an entry, however I am stuck at giving it the backspace function (go back and delete one previous char) and enter function (e.g when I'm done with input, press that button will help me to get back to the main screen).
/*
gcc -Wall keyboard1.c -o keyboard1 `pkg-config --cflags --libs gtk+-3.0`
Tested with GTK3.22 and GTK3.22 on Ubuntu18.04
*/
#include<gtk/gtk.h>
struct key{
gint id;
GtkWidget *button;
};
static const gchar letters[18]="QWERTYASDFGHZXCVBN";
//Need single chars as strings.
static gchar single_char[2]={'A', '\0'};
static void button_clicked(GtkWidget *button, gpointer *user_data)
{
gpointer *button_index=g_hash_table_lookup((GHashTable*)user_data[0], button);
g_print("Button index %i\n", (gint)(*button_index));
gint index=(gint)(*button_index);
single_char[0]=letters[index];
gchar *string=g_strdup_printf("%s%s", gtk_entry_get_text(GTK_ENTRY(user_data[1])), single_char);
gtk_entry_set_text(GTK_ENTRY(user_data[1]), string);
g_free(string);
}
int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
gint i=0;
gint j=0;
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Keyboard");
gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *entry=gtk_entry_new();
gtk_widget_set_hexpand(entry, TRUE);
//Save buttons in an array.
struct key k1;
GArray *keyboard=g_array_new(FALSE, FALSE, sizeof(struct key));
for(i=0;i<18;i++)
{
single_char[0]=letters[i];
k1.id=i;
k1.button=gtk_button_new_with_label(single_char);
g_array_append_val(keyboard, k1);
}
//A hash table to look up array index values.
struct key *p1=NULL;
GHashTable *hash_table=g_hash_table_new(NULL, NULL);
for(i=0;i<18;i++)
{
p1=&g_array_index(keyboard, struct key, i);
g_hash_table_insert(hash_table, p1->button, &(p1->id));
}
gpointer user_data[2]={hash_table, entry};
GtkWidget *grid1=gtk_grid_new();
for(i=0;i<3;i++)
{
for(j=0;j<6;j++)
{
p1=&g_array_index(keyboard, struct key, i*6+j);
gtk_grid_attach(GTK_GRID(grid1), p1->button, j, i, 1, 1);
g_signal_connect(p1->button, "clicked", G_CALLBACK(button_clicked), user_data);
}
}
GtkWidget *scroll=gtk_scrolled_window_new(NULL, NULL);
gtk_widget_set_vexpand(scroll, TRUE);
gtk_widget_set_hexpand(scroll, TRUE);
gtk_container_add(GTK_CONTAINER(scroll), grid1);
GtkWidget *expander=gtk_expander_new("Keyboard");
gtk_widget_set_vexpand(expander, TRUE);
gtk_widget_set_hexpand(expander, TRUE);
gtk_container_add(GTK_CONTAINER(expander), scroll);
GtkWidget *grid2=gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid2), expander, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid2), entry, 0, 1, 1, 1);
gtk_container_add(GTK_CONTAINER(window), grid2);
gtk_widget_show_all(window);
gtk_main();
g_hash_table_destroy(hash_table);
g_array_free(keyboard, TRUE);
return 0;
}
Here is the link to the post.
I have tried to replace a char in the gchar letters[18]="QWERTYASDFGHZXCVBN"; with \b, \n and \t as to replace backspace, newline and tab, but only \t works. \b gave me a strange symbol:
Could you give me suggestions on how to do it. Thank you very much!
You seem to confuse two things: gtk_entry_set_text sets the caption of a GTK element to a string of characters. It does not interpret it's characters.
That's why gtk_entry_set_text works well with non-control characters but stuck at \b. You had to send a GtkEvent using gtk_propagate_event to handle this properly (see here and here). \n is not a control character is this manner: It's possible that the GTK element your writing to just doesn't support newlines and Return would be interpreted as confirmation.

Probleme with structure, string anf gtkwidget

I'm trying to create a diaporama in c using gtk. I have a button "previous", which show the previous image. So I connect my button to a function and I pass it to a structure. But when I try to print an element of my array I have weird characters, and I don't know why. Plus, I got this warning for my gtk image :
GLib-GObject-WARNING **: 19:12:16.442: invalid uninstantiatable type '(null)' in cast to 'GtkImage'
Gtk-CRITICAL **: 19:12:16.442: IA__gtk_image_set_from_file: assertion 'GTK_IS_IMAGE (image)' failed
Here's my structure :
struct ButtonsArg {
GtkWidget *image;
char *img[];
};
Here's my code for the initialisation of my structure in the main :
GtkWidget *image = gtk_image_new();
char *images[nbImages];
//I get the name of all my image in this function
getImageList(images);
//This print work fine
printf("%s\n", images[0]);
struct ButtonsArg * arg;
arg = malloc(sizeof(struct ButtonsArg) + nbImages*sizeof(char*));
for(int i = 0; i < nbImages; i++) {
arg->img[i] = malloc(strlen(images[i])+1);
strcpy(arg->img[i], images[i]);
}
arg->image = image;
g_signal_connect(precedent, "clicked", G_CALLBACK(event_precedent), &arg);
Here's the function where the problems occur:
static void event_previous(GtkWidget *widget, gpointer data) {
g_print ("previous\n");
struct ButtonsArg *arg = data;
//Print weird charac
for(int i = 0; i < nbImages; i++) {
printf("%s\n", arg->img[i]);
}
GtkWidget *image = arg->image;
if(currentImage == 0) {
currentImage = nbImages - 1;
gtk_image_set_from_file (GTK_IMAGE (arg->image), arg->img[1]);
} else {
currentImage--;
gtk_image_set_from_file (GTK_IMAGE (arg->image), arg->img[2]);
}
}
If you have any advice, help or link that could help, thanks for sharing it with me.
Can you show the part of code where you try to change GtkImage variable? Seems like program was trying to set the null-value to GtkImage-type variable. In this cause any expression with this variable (like image->value) can raise segementation fault.
UPD: Ok. I see it. You should be check the arg-structure. I think, some attribute of this structure can have null-value.

GTK - Cannot print buffer value using function `printf`

I get the contents of my textview and I want to display the contents in the terminal using the printf function. But have stange symbols (Why?):
// get textbuffer from textview end print value in terminal
void on_lower_button_clicked(GtkWidget *lower_button, GtkTextView *textview_1)
{
GtkTextBuffer *textbuffer_1;
textbuffer_1 = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_1));
printf("%s\n", textbuffer_1); // strange symbols from my buffer ...
}
int main(int argc, char *argv[])
{
GtkWidget *lower_button;
GtkBuilder *builder;
GtkWidget *window;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if(!gtk_builder_add_from_file(builder, "template.ui", &error)) {
g_printerr("Error loading file: %s\n", error->message);
g_clear_error(&error);
return 1;
}
window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
lower_button = GTK_WIDGET(gtk_builder_get_object(builder, "lower_button"));
gtk_builder_connect_signals(builder, NULL);
// when I click on the button (lower_button) call
// on_lower_button_clicked function and transferred to her textview_1
g_object_unref(G_OBJECT(builder));
gtk_widget_show(window);
gtk_main();
return 0;
}
GtkTextBuffer is not a character array, it is a GTK object that can not be simply printed as text.
You need to extract the text from it if you want to print it or write it to file.
To do this, you will need to get a couple of GtkTextIter objects, and then use gtk_text_buffer_get_text.
Note, that if you have non English characters in your text, you may still have issues using printf, because the resulting text is UTF-8 encoded.
Here is an example code:
GtkTextIter start, end;
gchar *text;
gtk_text_buffer_get_start_iter(textview_1, &start);
gtk_text_buffer_get_end_iter(textview_1, &end);
text = gtk_text_buffer_get_text(textview_1, &start, &end, FALSE);
printf("%s\n",text);
g_free(text); //you need to clean up this buffer!

Error when calling gtk_grid_new()

When I try to run the following program:
#include <stdio.h>
#include <libxfce4panel/xfce-panel-plugin.h>
#include <unistd.h>
static void construct(XfcePanelPlugin *);
static void show_prefs(XfcePanelPlugin *);
XFCE_PANEL_PLUGIN_REGISTER(construct);
static void construct(XfcePanelPlugin *plugin) {
// Construct a simple gtk eventbox on the panel
// and add a appropriate sized icon
GtkWidget *ebox = gtk_event_box_new();
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size("/usr/share/pixmaps/idea.png", 16, 16, NULL);
GtkWidget *icon = gtk_image_new_from_pixbuf(pixbuf);
// display the previously constructed GTK widgets on the panel
gtk_container_add(GTK_CONTAINER(plugin), ebox);
gtk_container_add(GTK_CONTAINER(ebox), icon);
gtk_widget_show_all(ebox);
xfce_panel_plugin_set_expand(XFCE_PANEL_PLUGIN(plugin), TRUE);
xfce_panel_plugin_menu_show_configure(plugin);
g_signal_connect(plugin, "configure-plugin", G_CALLBACK(show_prefs), ebox);
}
static void show_prefs(XfcePanelPlugin *plugin) {
fputs("initializing config dialog...\n", stderr);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(win), 300, 200);
gtk_window_set_title(GTK_WINDOW(win), "Twittle Preferences");
GtkWidget *grid = gtk_grid_new();
gtk_widget_show_all(win);
}
The call to gtk_grid_new() results in the error
(wrapper-1.0:26288): GLib-GObject-WARNING **: cannot register existing type 'GtkWidget'
Can someone point me in the right direction?
makefile is available in the gist at https://gist.github.com/fasseg/953c6615e2b0c50ea62c#file-source-L31

Resources