Figuring out a C loop - c

This is one of the default gnome screensavers - "personal slideshow". It displays pictures from some location, pausing ~10s between pictures. Anyone know how it's looping & pausing?
I'm trying to increase the delay, but I'm hesitant to add sleep() without first knowing how it's doing it.
Thanks
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gs-theme-window.h"
#include "gs-theme-engine.h"
#include "gste-slideshow.h"
#include "xdg-user-dir-lookup.h"
int
main (int argc, char **argv)
{
GSThemeEngine *engine;
GtkWidget *window;
GError *error;
gboolean ret;
char *location = NULL;
char *background_color = NULL;
gboolean sort_images = FALSE;
gboolean no_stretch = FALSE;
GOptionEntry entries [] = {
{ "location", 0, 0, G_OPTION_ARG_STRING, &location,
N_("Location to get images from"), N_("PATH") },
{ "background-color", 0, 0, G_OPTION_ARG_STRING, &background_color,
N_("Color to use for images background"), N_("\"#rrggbb\"") },
{ "sort-images", 0, 0, G_OPTION_ARG_NONE, &sort_images,
N_("Do not randomize pictures from location"), NULL },
{ "no-stretch", 0, 0, G_OPTION_ARG_NONE, &no_stretch,
N_("Do not try to stretch images on screen"), NULL },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
error = NULL;
g_thread_init (NULL);
ret = gtk_init_with_args (&argc, &argv,
NULL,
entries,
NULL,
&error);
if (! ret) {
g_message ("%s", error->message);
g_error_free (error);
exit (1);
}
g_chdir (g_get_home_dir ());
g_set_prgname ("slideshow");
window = gs_theme_window_new ();
g_signal_connect (G_OBJECT (window), "delete-event",
G_CALLBACK (gtk_main_quit), NULL);
engine = g_object_new (GSTE_TYPE_SLIDESHOW, NULL);
if (location == NULL) {
location = xdg_user_dir_lookup ("PICTURES");
if (location == NULL ||
strcmp (location, "/tmp") == 0 ||
strcmp (location, g_get_home_dir ()) == 0) {
free (location);
location = g_build_filename (g_get_home_dir (), "Pictures", NULL);
}
}
if (location != NULL) {
g_object_set (engine, "images-location", location, NULL);
}
if (sort_images) {
g_object_set (engine, "sort-images", sort_images, NULL);
}
if (background_color != NULL) {
g_object_set (engine, "background-color", background_color, NULL);
}
if (no_stretch) {
g_object_set (engine, "no-stretch", no_stretch, NULL);
}
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (engine));
gtk_widget_show (GTK_WIDGET (engine));
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
gtk_widget_show (window);
gtk_main ();
return 0;
}

It looks like this program is using a slideshow engine from GStreamer. This is pointed to by the variable engine. GStreamer is a media processing framework that has lots of reusable components for audio and video. In this case, the slideshow engine reads images from a directory and displays them.
You can see the program tweaking various settings of the engine using g_object_set. Maybe there's another setting you can tweak to change the delay?
EDIT: The relevant source for the slide show is gste-slideshow.c. It looks like the key is start_new_load function, which is usually called with IMAGE_LOAD_TIMEOUT, a constant set to 10000 (milliseconds). There doesn't seem to be any way to set this value from the outside.

The show/delay/switch loop isn't in the code you've posted here, it's elsewhere.

The show/delay/switch is controlled by the GTK Slideshow, which is instantiated here:
engine = g_object_new (GSTE_TYPE_SLIDESHOW, NULL);
The delay is actually set in the gste_slideshow.c file, found here. The gste_slideshow_real_show function is located at line 890.
Enjoy.

Once you find where the timer is implemented you should change the value there. I'd be reluctant to use sleep() for the delay. Find where the loop is and modify the delay method that's already in the code. Adding extra sleeps may cause your screensaver to become unresponsive at times, especially if you aren't sure of what you're doing.

The main event loop is almost certainly inside of the gtk_main() function. However, you're barking up the wrong tree. The job of gtk_main() is pump events -- it detects low-level events (such as keyboard/mouse input and OS timers), converts them to higher-level events, and passes those onto the application code.
In this case, the application is the engine object, which is an object of type GSTE_TYPE_SLIDESHOW. Looking at the source code, we see that in the start_new_load() function, it creates a timer object that is ultimately responsible for the delays between pictures. This is initialized by a hard-coded value of 10000 ms.
If you want to change the timeout, you'll have to recompile the project and make the timeout configurable somehow.

I would think there's probably some sort of timer in the includes:
#include "gs-theme-window.h"
#include "gs-theme-engine.h"
#include "gste-slideshow.h"
There's nothing in this code that has anything about a delay. Check the implementation of engine and check the code in the slideshow include.

Related

How to get 2 textentry in gtk3

I'v been seaching google for 2 weeks now.
2 textentry in a gride.
(ex: userid, password)
Glade let me design that no problem...
For one textentry widget, it working.
I'm compiling/linking with mysql
so I would like to call functions, stored procedures
with entry1 and entry2.
Please help
thanks
:EDIT:
15:18 4 may 2019
I found a conclusive solution.
(But it's throwing seg fault)
bit of code following :
this is some kind of a transcription of the video into text (C code).
https://www.youtube.com/watch?v=_yTmW1QG3uk
obviously according to my goal really...
it's kind of working but let say you want to use the same
instance a second time, "seg fault"
I'm sure I will find the problem (gtk_main_quit) or something,
but the textentry multiples lines is solved :P
here's the code :
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <mysql/mysql.h>
GtkEntry *userid, *password;
static void Button_Pressed(GtkWidget *w, gpointer *data){
/* char *userid, *password;*/ //seg fault
/* userid[0]='\0';
password[0]='\0';*/
userid=gtk_entry_get_text(userid);
password=gtk_entry_get_text(password);
g_print("%s\n\r%s\n\r",userid, password);
}
static void CreateWindow(GtkApplication *myapp, gpointer *user_data){
GtkWidget *window;
window=gtk_application_window_new(myapp);
gtk_window_set_title(GTK_WIDGET(window), "Double Entry Solution");
gtk_window_set_default_size(GTK_WINDOW(window),400,400);
GtkWidget *vbox=gtk_vbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(vbox);
// userid pack
userid=gtk_entry_new();
gtk_box_pack_start(GTK_CONTAINER(vbox), userid, TRUE, TRUE,0);
gtk_widget_show(userid);
GtkWidget *hbox=gtk_hbox_new(TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
// password pack
password=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), password, TRUE, TRUE,0);
gtk_widget_show(password);
GtkWidget *submit=gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start(GTK_BOX(vbox), submit, TRUE, TRUE,0);
GtkWidget *button=gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(Button_Pressed), NULL);
gtk_container_add(GTK_CONTAINER(submit), button);
gtk_widget_show(button);
gtk_widget_show_all(window);
}
int main(int argc, char** argv){
GtkApplication *doubleentry;
doubleentry=gtk_application_new("smdelectro.business.site.doubleentry", G_APPLICATION_FLAGS_NONE);
g_signal_connect(doubleentry, "activate", G_CALLBACK(CreateWindow), NULL);
g_application_run(G_APPLICATION(doubleentry), argc, argv);
g_object_unref(doubleentry);
return (EXIT_SUCCESS);
}
The code below work :
#include <gtk/gtk.h>
int main(int argc, char **argv)
{
// Init
gtk_init(&argc,&argv);
// Create widgets
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkGrid *grid = GTK_GRID(gtk_grid_new());
// Attach entries
gtk_grid_attach(grid,gtk_entry_new(),0,0,1,1);
gtk_grid_attach(grid,gtk_entry_new(),0,1,1,1);
// Add the grid in the window
gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(grid));
// Dirty way to force clean termination when window is closed
g_signal_connect(window,"delete-event",G_CALLBACK(gtk_main_quit),NULL);
// Show **everythings** (not only the window)
gtk_widget_show_all(window);
// Main loop
gtk_main();
return 0;
}
Without any source code I can't provide more help, could you post it please.
A common trap in GTK+3 is creating widget without showing them. If you replace gtk_widget_show_all with gtk_widget_show you will see a window without widgets, they are here but not displayed, because by default the visible property is set to FALSE.
finally,
creating c file with reference to xml is ONE way, it's cool, thanks Glade.
Creating pure C Gtk3 is pain... omg
xml parser to generate c code...
aw..
BRB

How to refresh a GTK image?

Hi people from Stackoverflow, I have some knowledge of programming, but not very much. My idea is to program something like a video-game or visualizer in c, to do so I make and process somehow an array that represents an image and it has to be visualized and always being refreshed, like a video-game. I have the algorithm already done, I need to optimize it, I mean I know how to create the array representing an image at anytime, what I need now is to visualize it like an animation and later optimize with opencl.
The program that I want to make has to do something like this:
"create the image"
"render it",
"create the image"
"render it",
...
For that reason I know that I could start easily from a very simple example and I don't have to learn everything of GTK. I have been intensively searching for simple examples and trying to understand how it works but it didn't help, I need just to do that simple action, refresh it. A command somewhere should be enough.
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <glib.h>
const int Width = 1200, Height = 800;
char *buffer;
int i = 0;
GdkPixbuf *pixbuf;
GtkWidget *window;
GtkWidget* image;
void delay(int number_of_seconds){
int milli_seconds = 1000 * number_of_seconds;
clock_t start_time = clock();
while (clock() < start_time + milli_seconds);
}
int main (int argc, char *argv[]){
buffer = (char*)malloc(3 * Width * Height);
// CREATE AN IMAGE IN BUFFER SOMEHOW
// buffer = something;
//
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
pixbuf = gdk_pixbuf_new_from_data (buffer, GDK_COLORSPACE_RGB, FALSE, 8, Width, Height, (Width)*3, NULL, NULL);
image = gtk_image_new_from_pixbuf (pixbuf);
gtk_container_add(GTK_CONTAINER (window), image);
gtk_window_set_title (GTK_WINDOW (window), "Visualizador");
gtk_widget_show_all (window);
delay(0.04);
gtk_main ();
free (buffer);
return 0;
}
The program is really simple, when I create/load the image there it shows a picture, but I would like to put the function already programmed there, to return a "buffer" and then refresh the displayed image.
I read that gtk_widget_queue_draw has something to do, or gdk_pixbuf_simple_anim_add_frame or g_timeout_add but I have no idea how they work and what to put in this program.
Thank you in advance!
If you want a moving image or something that needs to get refreshed a lot then I would suggest using a GtkDrawingArea and implement it's draw signal, for that you'll need to use cairo. It should look something like this:
static gboolean
your_draw_cb(GtkWidget *widget, cairo_t *context, gpointer data)
{
// Do your drawing
return FALSE;
}
int main()
{
// Some code before ...
GtkWidget *area = gtk_drawing_area_new();
g_signal_connect(G_OBJECT(area), "draw", G_CALLBACK(your_draw_cb), your_data);
gtk_container_add(GTK_CONTAINER(your_container), area);
// More code ...
}
Each time you want to refresh it you should call
gtk_widget_queue_draw(area);
to get the draw signal called.
You won't need to store a buffer as that comes inside the cairo context.
But you may want to use other libraries for this purpose, like SDL2 or OpenGL as they are designed for videogames.
I hope this helps.

updating interface in GTK

I want to make an application that displays the time (ultimately I am trying to hack together my own simple smart mirror without using the existing smart mirror APIs). I am using GTK3 for the UI however I am having trouble figuring out a solution to make the UI update the time (I am not experienced in front end or GTK so bear with me).
I have tried placing loops around parts of the view3 code shown below however I have discovered that once gtk_main() is called I can't get out of the gtk main loop so that the while loop starts over and recalls the time function I wrote.
I have tried using functions like gtk_main_iteration_do(gtk_false()) (false so that it doesn't block) but I clearly don't understand enough about these functions because it's not working. If I leave gtk_main() out of the loop obviously gtk_main() never gets called and my application window won't even open up.
I have shown the relevant code in main below and following that the definition of the get_time_string() function I wrote.
int
main (int argc,
char *argv[])
{
// initialization and setting up window, packing widgets, etc
// view3
// populate buffer with time string
// and insert into text view
view3 = gtk_text_view_new();
gtk_widget_set_name(view3, "view3");
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view3));
gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
gtk_text_buffer_insert(buffer, &iter, get_time_string(), -1);
gtk_text_view_set_editable(GTK_TEXT_VIEW(view3), FALSE);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view3), FALSE);
// More widget packing, setting up UI
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Definition of get_time_string()
char* get_time_string(){
time_t time_var = time(NULL);
struct tm *info;
char *time_string = calloc(100, sizeof(char));
info = localtime( &time_var );
strftime(time_string, 100, "%I:%M %p", info);
return time_string;
}
You should not play with mainloop iterations unless you really need or know what to do.
The trick is to use g_timeout_add or g_idle_add and their variants. As you want the time to update at regular intervals (for minute resolution you will update every 60 seconds) then you can use g_timeout_add_seconds.
For illustration purposes, i'll add the seconds to your time string and update every second, using your get_time_string function but creating a very simple window to show just a time label:
#include <time.h>
#include <stdlib.h>
#include <gtk/gtk.h>
char* get_time_string(){
time_t time_var = time(NULL);
struct tm *info;
char *time_string = calloc(100, sizeof(char));
info = localtime( &time_var );
strftime(time_string, 100, "%I:%M:%S %p", info);
return time_string;
}
gboolean update_label_time (gpointer user_data) {
gchar *t = get_time_string();
gtk_label_set_text(GTK_LABEL(user_data), t);
g_free (t);
return G_SOURCE_CONTINUE;
}
int main (int argc, char *argv[])
{
gchar *t;
GtkWidget *window;
GtkWidget *label_time;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW(window), 300, 200);
t = get_time_string();
label_time = gtk_label_new (t);
g_free (t);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add (GTK_CONTAINER(window), label_time);
g_timeout_add_seconds(0.5, update_label_time, label_time);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
The result should be a window with a label updating every second:
GLib has its own time functions which you should use.

clutter stage in gtk can't not handle stage mouse press event

I have tried to use the clutter-gtk. I wrote a small piece of code that create a gtk window with a clutter stage in it. I try to get mouse button press event on the stage but there is nothing.
Here is the code:
#include <clutter/clutter.h>
#include <clutter-gtk/clutter-gtk.h>
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
/*gcc 3_clutter_app_clickable_text_in_gtk.c -o 3_clutter_app_clickable_text_in_gtk `pkg-config clutter-1.0 clutter-gtk-1.0 glib --cflags --libs`*/
/*mouse clic handler*/
void on_stage_button_press( ClutterStage *stage, ClutterEvent *event, gpointer data)
{
printf("ok\n");
}
int main(int argc, char *argv[])
{
if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
/*create the window*/
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
/*destroy from window close all*/
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
/*vertical box, 0 spacing*/
GtkWidget * box = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
/*add box in the window*/
gtk_container_add(GTK_CONTAINER(window), box);
/*create the cutter widget*/
GtkWidget *clutter_widget = gtk_clutter_embed_new ();
gtk_widget_set_size_request (clutter_widget, 200, 200);
ClutterActor *stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(clutter_widget));
clutter_stage_set_use_alpha(CLUTTER_STAGE(stage), TRUE);
ClutterColor stage_color ;
GString * bg_color = g_string_new("#555753ff");
clutter_color_from_string(&stage_color,bg_color->str);
clutter_actor_set_background_color(stage, &stage_color);
/*add the cutter widget in the box expand and fill are TRUE and spacing is 0*/
gtk_box_pack_start (GTK_BOX (box), clutter_widget, TRUE, TRUE, 0);
/*create line text*/
ClutterColor text_color;
GString * fg_color = g_string_new("#00000055");
clutter_color_from_string(&text_color, fg_color->str);
ClutterActor *some_text = clutter_text_new_full("Sans 24", "Hello, world", &text_color);
clutter_actor_set_size(some_text, 256, 128);
clutter_actor_set_position(some_text, 128, 128);
clutter_actor_add_child(CLUTTER_ACTOR(stage), some_text);
clutter_text_set_editable(CLUTTER_TEXT(some_text), TRUE);
/*define clic event*/
g_signal_connect(stage, "button-press-event", G_CALLBACK(on_stage_button_press), NULL);
/* Show the window and all its widgets: */
gtk_widget_show_all (GTK_WIDGET (window));
/* Start the main loop, so we can respond to events: */
gtk_main ();
return EXIT_SUCCESS;
}
Nothing happens when I click on the stage. I have made some tests and I can handle click event on the main windows, on the clutter_widget but not directly on the clutter stage.
This code is modified one from http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/sec-stage-widget.html. In this one the author connect the signal directly on the stage but this example is for clutter 0.9 and don't compile anymore with clutter v > 1.0.
Any ideas on what I am doing wrong?
Edit
I have made some test with "key-press-event" which are handled. So the problem seems to come from the events mask of the stage.
Does anyone know how to change the event mask of the stage in order to force the stage to react on mouse events?
I close this question because :
clutter-gtk is just a proof of concept
clutter-gtk will not be used in the future
see https://mail.gnome.org/archives/clutter-list/2013-February/msg00059.html
so I don't want to loose more time with this.
For information,the same example using juste clutter works as expected.
CLUTTER_BACKEND=gdk ./yourexecutable

How to draw / render to a widget using the widgets Xid in GTK/Cairo in 'C'

I have a need to write a GTK application in C that does some animation using Cairo that will render into a GTK widget that exists in another running application. The idea is to do the very same thing you can do with VLC and Mplayer. For example Mplayer has the -wid option:
-wid (also see -guiwid) (X11, OpenGL and DirectX only)
This tells MPlayer to attach to an existing window. Useful to embed MPlayer in a browser (e.g. the plugger extension). This option
fills the given window completely, thus aspect scaling, panscan, etc
are no longer handled by MPlayer but must be managed by the
application that created the window.
With this Mplayer option you can create a GTK application with a GTKImage widget, get it's Xid and then play a movie in the GTK application using Mplayer with the Xid specified.
I'm trying to do the same thing except render/draw into the external window using Cairo. Anybody have suggestions or better yet a small code sample?
Take a look to the GtkSocket and GtkPlug classes.
The main program will create a GtkSocket and the XID you can pass to the other program will be returned by the function gtk_socket_get_id(). Then the other program will use it as argument to the gtk_plug_new() function. All the render will be done in children of this new GtkPlug object.
UPDATE: Well, if you want... here it is a minimal example of GtkSocket/GtkPlug. You don't say if you are using GTK+2 or GTK+3, so I'm assuming version 2.
server.c:
#include <gtk/gtk.h>
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *sck = gtk_socket_new();
gtk_container_add(GTK_CONTAINER(wnd), sck);
gtk_window_set_default_size(GTK_WINDOW(wnd), 400, 300);
gtk_widget_show_all(wnd);
GdkNativeWindow nwnd = gtk_socket_get_id(GTK_SOCKET(sck));
g_print("%lu\n", nwnd);
gtk_main();
return 0;
}
client.c:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <cairo/cairo.h>
#include <math.h>
gboolean OnDraw(GtkWidget *w, GdkEvent *ev, gpointer data)
{
GtkAllocation size;
gtk_widget_get_allocation(w, &size);
cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(w));
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_arc(cr, size.width/2, size.height/2, size.height/2, 0, 2*M_PI);
cairo_fill(cr);
cairo_destroy(cr);
return TRUE;
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GdkNativeWindow nwnd = strtoul(argv[1], NULL, 10);
GtkWidget *plug = gtk_plug_new(nwnd);
GtkWidget *canvas = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(plug), canvas);
g_signal_connect(canvas, "expose-event", (GCallback)OnDraw, NULL);
gtk_widget_show_all(plug);
gtk_main();
return 0;
}
The XID to be used is printed by the server and has to be copied/pasted as argument to the client:
$ ./server
60817441
^Z
[1]+ Stopped ./server
$ bg
$ ./client 60817441

Resources