dude here im gonna create client and combine with GIO Channel, and after i put it all together, it seems appears to work on socket, but the g_io_channel not as watching, like crashing or such..
please see following code :
#include <stdio.h>
#include <gio/gio.h> // g_timeout_add
#include <gtk/gtk.h> // gtk
#include <netinet/in.h> //sockaddr_in
#include <sys/socket.h> // socket();
#include <arpa/inet.h> // inet_addr();
#include <string.h> // memset();
struct dada
{
gint id_sock;
guint id_gio_watch;
};
gboolean incoming(GIOChannel *chan, GIOCondition condition, struct dada *didi )
{
int byte;
int insock = g_io_channel_unix_get_fd(chan);
#define MAXMAX 128
char buff[128];
printf("sock : %d\n",insock);
byte = recv(insock,buff,MAXMAX-1,0);
if(byte <= 0)
{
perror("recv");
close(didi->id_sock);
g_source_remove(didi->id_gio_watch);
return FALSE;
}
else
{
buff[byte] = '\0';
printf("coming : %s",buff);
}
return TRUE;
}
// gtk area
void hello(GtkWidget *widget, gpointer data)
{
g_print("Haii world %s\n", (char *)data);
}
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print("a delete event has been occured properly :D\n");
return(0);
}
void destroy(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
// end of gtk area
int main(int argc, char **argv)
{
//gtk bussines from here
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
button = gtk_button_new_with_label("ohayo");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(hello), (gpointer)"hha" );
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
gtk_container_add(GTK_CONTAINER(window),button);
gtk_widget_show(button);
gtk_widget_show(window);
//gtk bussiness done here...
// network code //
struct dada didi;
memset(&didi,0,sizeof(didi));
struct sockaddr_in my; // set my network device info
gint rootsock; // handle the root socket
//socket
rootsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//binding
memset(&my,0,sizeof(my));
my.sin_addr.s_addr = inet_addr("127.0.0.1");
my.sin_family = AF_INET;
my.sin_port = htons(1111);
//bind(rootsock,(struct sockaddr*)&my,sizeof(my));
printf("sock : %d\n",rootsock);
connect(rootsock,(struct sockaddr*)&my,sizeof(my));
didi.id_sock = rootsock;
didi.id_gio_watch = g_io_add_watch(g_io_channel_unix_new(didi.id_sock),G_IO_IN|G_IO_OUT,(GIOFunc)incoming,&didi);
// network code //
gtk_main();
return 0;
}
compiling :
$ gcc -o konek_gioglib konek_gioglib.c `pkg-config glib-2.0 --libs --cflags gtk+-2.0`
my own pc run as server with port 1111 and stream connection ( TCP ) :
$ nc -v -l 1111
running my app :
$ ./konek_gioglib
sock : 6
sock : 6
server got connection and send some word :
$ nc -v -l 1111
Connection from 127.0.0.1 port 1111 [tcp/*] accepted
a
a
and when the server send something, gtk window show but with error like these :
is there anyone dont mind to explain, why these things could happened to mine ?
well last night I brainstormed myself with my own heart, and finally could make these thing work,
here the proper code
#include <stdio.h>
#include <gio/gio.h> // g_timeout_add
#include <gtk/gtk.h> // gtk
#include <netinet/in.h> //sockaddr_in
#include <sys/socket.h> // socket();
#include <arpa/inet.h> // inet_addr();
#include <string.h> // memset();
#include <fcntl.h>
#include <stdlib.h>
struct dada
{
gint id_sock;
guint id_gio_connect;
guint id_gio_watch;
};
gboolean readdata(GIOChannel *chan,GIOCondition condition, struct dada *didi)
{
gchar dada[20] = {0};
int dadaz =0;
if( condition != G_IO_IN )
return FALSE;
if(dadaz = recv(g_io_channel_unix_get_fd(chan),dada,19,0)<=0)
{
perror("recv");
close(didi->id_sock);
g_source_remove(didi->id_gio_connect);
g_source_remove(didi->id_gio_watch);
exit(0);
return FALSE;
}
printf("data in : %s\n",dada);
return TRUE;
}
gboolean incoming(GIOChannel *chan, GIOCondition condition, struct dada *didi )
{
if( condition & G_IO_ERR || condition & G_IO_HUP )
return FALSE;
didi->id_gio_watch = g_io_add_watch(chan,G_IO_IN | G_IO_ERR | G_IO_HUP,(GIOFunc)readdata,didi);
return FALSE;
}
// gtk area
void hello(GtkWidget *widget, gpointer data)
{
g_print("Haii world %s\n", (char *)data);
}
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print("a delete event has been occured properly :D\n");
return(0);
}
void destroy(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
// end of gtk area
int main(int argc, char **argv)
{
//gtk bussines from here
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
button = gtk_button_new_with_label("ohayo");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(hello), (gpointer)"hha" );
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
gtk_container_add(GTK_CONTAINER(window),button);
gtk_widget_show(button);
gtk_widget_show(window);
//gtk bussiness done here...
// network code //
struct dada didi;
memset(&didi,0,sizeof(didi));
struct sockaddr_in your; // set my network device info
gint rootsock; // handle the root socket
//socket
rootsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
memset(&your,0,sizeof(your));
printf("sock : %d\n",rootsock);
your.sin_family = AF_INET;
your.sin_addr.s_addr = inet_addr("127.0.0.1");
your.sin_port = htons(1111);
connect(rootsock,(struct sockaddr*)&your,sizeof(your));
didi.id_sock = rootsock;
didi.id_gio_connect = g_io_add_watch(g_io_channel_unix_new(didi.id_sock),G_IO_IN | G_IO_OUT | G_IO_ERR | G_IO_HUP,(GIOFunc)incoming,&didi);
// network code //
gtk_main();
return 0;
}
and the only different had made is the "worked" code , need :
- gio for connecting, and gio for watching
instead of be "non-worked" code ( only gio for connecting ), but again i just wondering "why", why on connect() need two gio (recursively) in order make these "gio things" work,
these is really odd, if I see back then on g_io_channel + socket = server , still just get one client ? in C language
which on accept() just need only one gio and only for watching.
if someone could explain these, how great it'll be :)
Related
In a purely GDK 3.10 (no GTK) project how do I refresh/clear/redraw a transparent background of a GdkWindow?
This test.c sets the background correctly on initialization (gdk_window_show()) and when I iconify+deiconify the window but not on resizing or moving it around per mouse:
#include <gdk/gdk.h>
// #include <gdk/gdkx.h> // GDK X11
// #include <X11/Xlib.h> // Xlib
// #include <X11/Xutil.h>
void eventHandler(GdkEvent *evt, gpointer data) {
GdkWindow *win = (GdkWindow *)data;
switch(evt->type)
{
case GDK_CONFIGURE: {
// refresh window background here
printf("refresh background here\n");
break;
}
case GDK_DELETE: {
gdk_window_destroy(win);
_exit(0);
break;
}
default:
break;
}
}
int main(int argc, char *argv[]) {
gdk_init(NULL, NULL);
GdkDisplay *disp=gdk_display_get_default();
GdkScreen *scr = gdk_display_get_default_screen (disp);
GdkWindow *root = gdk_screen_get_root_window(scr);
GdkWindowAttr attr;
attr.width=200;
attr.height=200;
attr.x=0;
attr.y=0;
attr.window_type = GDK_WINDOW_TOPLEVEL;
attr.wclass=GDK_INPUT_OUTPUT;
GdkVisual *vis = gdk_screen_get_rgba_visual (scr);
attr.visual = vis;
GdkWindow *newWin=gdk_window_new(root,&attr, GDK_WA_X | GDK_WA_Y);
GdkRGBA color = { .red=1.0, .green=0.0, .blue=1.0, .alpha=0.0};
gdk_window_set_background_rgba(newWin, &color);
gdk_event_handler_set (eventHandler, newWin, NULL);
gdk_window_show(newWin);
GMainLoop *mainloop = g_main_new (TRUE);
g_main_loop_run (mainloop);
gdk_display_close(disp);
return 0;
}
gcc build command:
gcc -o test test.c `pkg-config gdk-3.0 --libs --cflags`
Outcome:
Note: I'm targeting X11 so I'm also allowed to include Xlib or GDK X11 backend functions.
Thank you for any help or pointers.
The solution to this is a fix of a rather silly mistake I made passing an incomplete attribute mask to gdk_window_new().
To make it work the line in question has to be changed to:
GdkWindow *newWin=gdk_window_new(root,&attr, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_WMCLASS);
Currently I am writing a program in C, on a linux system (Raspberry Pi to be exact) which should draw to a GTK window using Cairo. I've been following the tutorial at: http://zetcode.com/gfx/cairo/ . But it is way to vague with it's explanations at certain points.
It does not explain two points that I really need:
I can't figure out a way to draw to the window with a proper function call.
It removes what is already drawn.
I need a piece of code that does some simple things, in a very Object-Oriented manner:
Draw lines to a GTK window with a function call, given X and Y for both starting and end point;
Do not remove what is previously drawn;
All initializations of variables and the window should be outside the main function.
So basically something similar to this:
#include <cairo.h>
#include <gtk/gtk.h>
void drawLine(int xStart, int yStart, int yEnd, int xEnd) {
//Drawing code here.
}
void initializeCairo() {
//Insert cairo initialization.
}
void initializeGTK() {
//Insert GTK initialization.
}
/*If needed a general initializer for both cairo and GTK*/
void initialize() {
//Insert general initialization.
}
int main (int argc, char *archv[]) {
intializeGTK();
initializeCairo();
if(doSomething) {
drawLine(10, 10, 20, 20);
}
}
If it could be explained what a method does (in proper English please, not a reference to the documentation), that'd be absolutely great.
Also please include the gcc build command used.
Thanks in advance!
The answers from andlabs are fine. Here is in addition a short (although not entirely elegant) example. It will "kind of remember" the last NUM lines - creation/resize/activation/deactivation of the window will trigger a "draw" of the content. A Next button click will add a new line to the output. Check also the command-line output for an update of
the array values that are drawn.
#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <cairo.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#define NUM 3
typedef struct {
GtkApplication *app;
GtkWidget *window;
GtkWidget *button;
GtkWidget *da;
cairo_t* cr;
gboolean redraw;
gint xsize;
gint ysize;
} appWidgets;
gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data);
void nextCallback (GtkWidget *widget, gpointer data);
void nextCallback (GtkWidget *widget, gpointer data)
{
appWidgets *w = (appWidgets*) data;
static gint cnt = 0;
static gdouble x[NUM], y[NUM], u[NUM], v[NUM];
// determine the next coordinates for a line
if (w->redraw == FALSE) {
x[cnt] = g_random_double();
y[cnt] = g_random_double();
u[cnt] = g_random_double();
v[cnt] = g_random_double();
}
w->cr = gdk_cairo_create (gtk_widget_get_window (w->da));
// map (0,0)...(xsize,ysize) to (0,0)...(1,1)
cairo_translate (w->cr, 0, 0);
cairo_scale (w->cr, w->xsize, w->ysize);
// set linewidth
cairo_set_line_width (w->cr, 0.005);
// draw the lines
for (int k = 0; k < NUM; k++) {
cairo_move_to (w->cr, x[k], y[k]);
cairo_line_to (w->cr, u[k], v[k]);
cairo_stroke (w->cr);
g_print("k=%d:(%1.2lf,%1.2lf).(%1.2lf,%1.2lf) ",
k, x[k], y[k], u[k], v[k]);
}
g_print("\n");
cairo_destroy (w->cr);
if (w->redraw == FALSE) {
cnt++;
if (cnt == NUM)
cnt = 0;
}
}
gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data)
{
appWidgets *w = (appWidgets*) data;
w->xsize = gtk_widget_get_allocated_width (w->da);
w->ysize = gtk_widget_get_allocated_height (w->da);
w->redraw = TRUE;
nextCallback (NULL, w);
w->redraw = FALSE;
return TRUE;
}
void activate (GtkApplication *app, gpointer data)
{
GtkWidget *box;
appWidgets *w = (appWidgets*) data;
w->window = gtk_application_window_new (w->app);
gtk_window_set_application (GTK_WINDOW (w->window), GTK_APPLICATION (w->app));
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (w->window), box);
w->da = gtk_drawing_area_new();
gtk_widget_set_size_request (w->da, 400, 400);
gtk_box_pack_start (GTK_BOX (box), w->da, TRUE, TRUE, 0);
g_signal_connect (w->da, "draw", G_CALLBACK (drawEvent), (gpointer) w);
w->button = gtk_button_new_with_label ("Next");
g_signal_connect (G_OBJECT (w->button), "clicked", G_CALLBACK (nextCallback),
(gpointer) w);
gtk_box_pack_start (GTK_BOX (box), w->button, FALSE, TRUE, 0);
gtk_widget_show_all (GTK_WIDGET (w->window));
w->redraw = FALSE;
}
int main (int argc, char *argv[])
{
gint status;
appWidgets *w = g_malloc (sizeof (appWidgets));
w->app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (w->app, "activate", G_CALLBACK (activate), (gpointer) w);
status = g_application_run (G_APPLICATION (w->app), argc, argv);
g_object_unref (w->app);
g_free (w);
w = NULL;
return status;
}
Build the program as usual:
gcc example.c -o example `pkg-config --cflags --libs gtk+-3.0`
Here is my code.
#include <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#define MAX_LENGTH 8
#define WIDGET_NUM 3
typedef struct Widget
{
GtkWidget *window;
GtkWidget *button[WIDGET_NUM];
GtkWidget *entry[WIDGET_NUM];
GtkWidget *label[WIDGET_NUM];
GtkWidget *grid;
pthread_t pid[WIDGET_NUM];
int button_num;
}Widget;
void num_2_time(int num, char *buf)
{
int h = num / 3600;
int m = num % 3600 / 60;
int s = num % 60;
sprintf(buf, "%d:%d:%d", h, m, s);
}
void *wait_4_waking(void *arg)
{
Widget *window = (Widget*)arg;
int input_num, window_num = window->button_num;
const char *text;
char buf[MAX_LENGTH * 2];
text = gtk_entry_get_text(GTK_ENTRY(window->entry[window_num]));
input_num = atoi(text);
gtk_entry_set_text(GTK_ENTRY(window->entry[window_num]), "");
while (input_num >= 0)
{
num_2_time(input_num, buf);
//Segmentation fault
gtk_label_set_text(GTK_LABEL(window->label[window_num]), buf);
sleep(1);
input_num--;
}
return NULL;
}
void button_clicked_0(GtkWidget *widget, gpointer data)
{
Widget *window = (Widget*)data;
window->button_num = 0;
printf("%u\n", window->pid[0]);
if (window->pid[0] > 0)
{
pthread_cancel(window->pid[0]);
}
pthread_create(window->pid, NULL, wait_4_waking, data);
}
void button_clicked_1(GtkWidget *widget, gpointer data)
{
Widget *window = (Widget*)data;
window->button_num = 1;
if (window->pid[1] > 0)
{
pthread_cancel(window->pid[1]);
}
pthread_create(window->pid+1, NULL, wait_4_waking, data);
}
void button_clicked_2(GtkWidget *widget, gpointer data)
{
Widget *window = (Widget*)data;
window->button_num = 2;
if (window->pid[2] > 0)
{
pthread_cancel(window->pid[2]);
}
pthread_create(window->pid+2, NULL, wait_4_waking, data);
}
int main (int argc, char **argv)
{
Widget window;
int i;
void (*button_clicked[WIDGET_NUM])(GtkWidget*, gpointer) = {
button_clicked_0, button_clicked_1, button_clicked_2
};
gtk_init(&argc, &argv);
window.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window.window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window.window), 400, 200);
window.grid = gtk_grid_new();
for (i = 0; i < WIDGET_NUM; i++)
{
window.entry[i] = gtk_entry_new();
window.label[i] = gtk_label_new("0:0:0");
window.button[i] = gtk_button_new_with_label("Go!");
window.pid[i] = 0;
gtk_entry_set_max_length(GTK_ENTRY(window.entry[i]), MAX_LENGTH);
gtk_grid_attach(GTK_GRID(window.grid), window.entry[i], 0, i, 1, 1);
gtk_grid_attach(GTK_GRID(window.grid), window.button[i], 1, i, 1, 1);
gtk_grid_attach(GTK_GRID(window.grid), window.label[i], 2, i, 1, 1);
}
gtk_container_add (GTK_CONTAINER (window.window), window.grid);
for (i = 0; i < WIDGET_NUM; i++)
{
g_signal_connect (window.button[i], "clicked", G_CALLBACK (button_clicked[i]), (gpointer)&window);
}
g_signal_connect (window.window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all (window.window);
gtk_main();
return 0;
}
Building command:
gcc -o 1 test2.c `pkg-config --libs --cflags gtk+-3.0` -pthread -g
This error occurred when I clicked The button, but it didn't occur all the time. Before it occurred, I get an information below.
(1:18144): Pango-CRITICAL **: pango_layout_get_pixel_extents: assertion 'PANGO_IS_LAYOUT (layout)' failed
(1:18144): Pango-CRITICAL **: pango_layout_get_iter: assertion 'PANGO_IS_LAYOUT (layout)' failed
And then segmentation fault.
I checked its information by dmesg command. And I got this.
[ 703.437988] 1[6358]: segfault at 10 ip 00007f9b07ac3f91 sp 00007ffe3bd53790 error 4 in libpango-1.0.so.0.3800.1[7f9b07aa0000+48000]
How can I do for this error?
You are calling a Gtk+ widget function from another thread. Gtk+ is not thread safe so don't do that.
Your best option is to avoid threads: design your code so that the main loop is never blocked for long periods. Usually when I see threading problems, the use of threads is unnecessary and the whole mess could have been avoided by a cleaner design.
If the code can't be designed in a better way, then you'll need to use e.g. g_main_context_invoke() in your other thread to invoke a function in the main thread: that function can then modify the Gtk+ widget state safely. Be careful not to make mistakes with lifetimes of pointers that you share between threads.
Currently trying to create a custom widget which is based directly on GtkWidget, marks it as drawable and draws content with cairo. So much for the context.
As soon as I try to handle events (so I can implement zoom) - especially the scroll event - just does not work and I am not sure as of why.
The callback does get executed on focus-in/focus out (good old print statement proves that), but I do never ever get any scroll wheel activity detected by that callback (button clicks are key press/release do not work either).
I tried to hook up to the event signal by
using the function pointer and assigning callback function (which I think is the right thing to do)
using g_signal_connect (mywidget, "event",..) from foo_new or foo_init
Neither did work.
The Foo init:
foo_init (Foo *self)
{
GtkWidget *widget = GTK_WIDGET (self);
gtk_widget_set_has_window (widget, FALSE);
self->priv = FOO_GET_PRIVATE (self);
gtk_widget_add_events (widget, GDK_ALL_EVENTS_MASK);
g_assert ((gtk_widget_get_events (widget) & GDK_SCROLL_MASK) != 0); //just fine
/* added some stuff I also tried but did not work */
gtk_widget_set_sensitive (widget, TRUE);
gtk_widget_set_can_focus (widget, TRUE);
gtk_widget_grab_focus (widget);
...
How can I get all the events of my widget?
Assigning widget_class->key_press_event = my_handler_callback; actually works as expected and I get the keys I press, but the very same widget_class->button_press_event = my_handler_callback; or widget_class->scroll_event = my_handler_callback; assignments do not work!
widget_class->key_press_event = my_handler_callback; // works
widget_class->key_release_event = my_handler_callback; // works
widget_class->button_press_event = my_handler_callback; // NOT
widget_class->button_release_event = my_handler_callback; // NOT
widget_class->scroll_event = my_handler_callback; // NOT
This made me suspicious.
To receive this signal, the GdkWindow associated to the widget needs
to enable the GDK_BUTTON_PRESS_MASK mask.
Is it necessary to realize the widget before gtk_widget_add_events "works"...?
Update: Tried to call gtk_widget_add_events after gtk_widget_show_all. No change.
Update: fully compileable example
#ifndef __FOO_H__
#define __FOO_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define FOO_TYPE (foo_get_type ())
#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE, Foo))
#define FOO_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE, Foo const))
#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE, FooClass))
#define FOO_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE))
#define FOO_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE))
#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE, FooClass))
typedef struct _Foo Foo;
typedef struct _FooClass FooClass;
typedef struct _FooPrivate FooPrivate;
struct _Foo
{
GtkWidget parent;
FooPrivate *priv;
};
struct _FooClass
{
GtkWidgetClass parent_class;
};
GType foo_get_type (void) G_GNUC_CONST;
Foo *foo_new (void);
G_END_DECLS
#endif /* __FOO_H__ */
#include "foo.h"
gboolean
scroll_hook (GtkWidget *widget, GdkEventScroll *event)
{
g_print ("%p registered a scroll event\n");
return TRUE;
}
#define FOO_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), FOO_TYPE, FooPrivate))
struct _FooPrivate
{
char to_silence_warning;
};
G_DEFINE_TYPE (Foo, foo, GTK_TYPE_WIDGET)
static void
foo_finalize (GObject *object)
{
G_OBJECT_CLASS (foo_parent_class)->finalize (object);
}
static void
foo_class_init (FooClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = foo_finalize;
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
widget_class->scroll_event = scroll_hook;
g_type_class_add_private (object_class, sizeof (FooPrivate));
}
static void
foo_init (Foo *self)
{
self->priv = FOO_GET_PRIVATE (self);
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
}
Foo *
foo_new ()
{
return g_object_new (FOO_TYPE, NULL);
}
#include <gtk/gtk.h>
#include "foo.h"
#include <stdlib.h>
gboolean
chicken_out (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
g_print ("bye");
gtk_main_quit();
return TRUE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
Foo *my;
int i;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
my = foo_new ();
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (my));
gtk_widget_show_all (window);
gtk_widget_add_events (GTK_WIDGET (my), GDK_ALL_EVENTS_MASK);
g_assert ((gtk_widget_get_events (GTK_WIDGET (my)) & GDK_SCROLL_MASK) != 0);
g_signal_connect (window, "delete-event", G_CALLBACK(chicken_out), NULL);
gtk_main ();
return EXIT_SUCCESS;
}
Use
gcc `pkg-config --cflags --libs gtk+-3.0` -I. ./foo.c ./foo_test.c -o foo.bin
to compile (granted, all files are in your cwd)
Moving from GtkWidget to GtkDrawingArea was required, as without it would crash. The root cause was that the ->window private variable of widget is not populated without a proper realize default callback - which I did not implement.
I have a GTK+ application written in C that loads a matrix of animated GIF files. These GtkImages automatically run the animation when they are loaded and then stop when the animation is completed. How would I restart the animation of each GtkImage containing the GIF and are signals generated when the animation is complete?
Thank you.
EDIT :
Would the use of gdk_pixbuf_animation_get_iter() described here make this possible?
Full code is provided below.
/*
* Compile me with:
* gcc -o reels reels.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
/* GTK */
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
/**** prototypes ****/
static void destroy (GtkWidget*, gpointer);
GdkPixbuf *create_pixbuf(const gchar * filename);
GtkWidget *SetupWindow(gchar *data, const gchar *filename);
static void destroy (GtkWidget *window, gpointer data);
void btnSpin_clicked(GtkWidget *button, gpointer data);
void btnExit_clicked(GtkWidget *button, gpointer data);
/********************/
GtkWidget *images[3][5];
static void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
void btnSpin_clicked(GtkWidget *button, gpointer data)
{
printf("Spin Button pressed.\n");
return;
}
void btnExit_clicked(GtkWidget *button, gpointer data)
{
gtk_main_quit();
return;
}
GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
GdkPixmap *background;
GdkPixbuf *pixbuf;
GdkScreen *ourscreen;
GdkColormap *colormap;
GtkStyle *style;
GdkColor fg;
GdkColor bg;
GError *error = NULL;
GdkRectangle *rect;
GtkWidget *window;
pixbuf = gdk_pixbuf_new_from_file (filename,&error);
if (error != NULL) {
if (error->domain == GDK_PIXBUF_ERROR) {
g_print ("Pixbuf Related Error:\n");
}
if (error->domain == G_FILE_ERROR) {
g_print ("File Error: Check file permissions and state:\n");
}
g_printerr ("%s\n", error[0].message);
}
gdk_pixbuf_render_pixmap_and_mask (pixbuf, &background, NULL, 0);
style = gtk_style_new ();
style->bg_pixmap[0] = background;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), data);
// gtk_window_maximize(GTK_WINDOW(window));
gtk_window_set_modal (GTK_WINDOW (window),TRUE);
gtk_window_set_default_size(GTK_WINDOW(window),628,530);
gtk_widget_set_style (GTK_WIDGET(window), GTK_STYLE(style));
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER_ALWAYS);
gtk_container_set_border_width(GTK_CONTAINER(window), 0);
//gtk_window_set_resizable(GTK_WINDOW(window), (gboolean) FALSE);
gtk_window_set_decorated( GTK_WINDOW(window), FALSE );
return(window);
}
int main (int argc, char *argv[])
{
GdkPixbufAnimation *animation;
GtkWidget *image;
int x,y;
GdkPixbuf *pixBuf;
GdkPixmap *pixMap;
gchar filename[20];
GtkWidget *btnSpin, *btnExit;
GtkWidget *frame; /* for absolute positionining of widgets */
GtkWidget *window;
int posx, posy;
gtk_init (&argc, &argv);
window = SetupWindow("Demo", "background.gif");
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
frame = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), frame);
btnSpin = gtk_button_new_with_label("Spin");
gtk_widget_set_size_request(btnSpin, 80, 35);
gtk_fixed_put(GTK_FIXED(frame), btnSpin, 229, 485);
g_signal_connect(G_OBJECT( btnSpin ), "clicked", G_CALLBACK(btnSpin_clicked), NULL );
btnExit = gtk_button_new_with_label("Exit");
gtk_widget_set_size_request(btnExit, 80, 35);
gtk_fixed_put(GTK_FIXED(frame), btnExit, 320, 485);
g_signal_connect(G_OBJECT( btnExit ), "clicked", G_CALLBACK(btnExit_clicked), NULL );
/* setup animated gifs */
for( y = 0; y < 3; y++ )
{
posy = (y*120) + 20;
for( x = 0; x < 5; x++ )
{
posx = (x*120) + 20;
/* set each Image widget to spin GIF */
sprintf( filename,"%d-%d.gif", y+1,x+1 );
images[y][x] = gtk_image_new_from_file(filename);
gtk_fixed_put(GTK_FIXED(frame), images[y][x], posx, posy);
}
}
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
After taking a look at the GtkImage source code, I am afraid there is no signal that is generated when the animation is completed. However, you should be able to restart the animation by calling gtk_image_set_from_file() or gtk_image_set_from_animation().
To completely solve your initial issue, I propose you create a subclass of GtkImage. It should behave exactly like GtkImage, except that animation_timeout should send a signal if delay < 0 around line 1315.
Information about creating a subclass of a GObject (note that GtkImage is a GObject) can be found here.
Based on user1202136's answer the following code snippets show the solution. I post this in case others find it useful.
The basic idea is to use GdkPixbufAnimation, gdk_pixbuf_animation_new_from_file and gtk_image_set_from_animation
The following code snippet(s) show how to do it.
GtkWidget *images[3][5];
GdkPixbufAnimation *animations[3][5];
/* Initial setup of animated gifs */
for( y = 0; y < 3; y++ )
{
for( x = 0; x < 5; x++ )
{
/* set each Image widget to spin GIF */
sprintf( filename,"%d-%d.gif", y+1,x+1 );
images[y][x] = gtk_image_new();
animations[y][x] = gdk_pixbuf_animation_new_from_file ( filename , &error);
gtk_image_set_from_animation (GTK_IMAGE(images[y][x]), animations[y][x]);
gtk_fixed_put(GTK_FIXED(frame), images[y][x], (x*120) + 20, (y*120) + 20);
}
}
/* now to restart the animations use the images and animations array already stored in memory,
no need to re-read the animations from disk so this happens quickly
*/
/* restart animated gifs */
for( y = 0; y < 3; y++ )
{
for( x = 0; x < 5; x++ )
{
gtk_image_set_from_animation(GTK_IMAGE(images[y][x]), animations[y][x]);
}
}