I have a gtk2+ code in which I have a running button and a stopping one. I want that the stop button pause the RUN function (not to leave it) in a specific point until run button is pressed again, continuing in the same point.
The problem is that while loops block any kind of interaction with program interfaces and freezes.
void STOP(GtkWidget *widget, GObject *context_object_stop)
{
stop=1;
}
void RUN(GtkWidget *widget, GObject *context_object_run)
{
GtkEntry *buffer= g_object_get_data (context_object_run, "buffer");
GtkTextIter iter;
GtkTextMark *marker;
marker = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &iter, marker);
stop=0;
int i=0;
for (i=0; i<5000000; i=i+1)
{
while (stop==1)
{
//here is my problem
}
gchar * stuff = g_strdup_printf("%d""\n", i);
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
while (gtk_events_pending())
gtk_main_iteration();
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), marker);
}
}
Any ideas to approach the solution?
EDIT; An approach of multithreading that does not stop running the main function:
stop=0;
int i=0;
pthread_t th1;
for (i=0; i<5000000; i=i+1)
{
void *StopRun(void *arg)
{
while (stop==1)
{
//here is my problem
}
}
if (stop==1)
{
pthread_create(&th1, NULL, (void*)StopRun, NULL);
}
gchar * stuff = g_strdup_printf("%d""\n", i);
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
while (gtk_events_pending())
gtk_main_iteration();
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), marker);
}
Have a look the documentation and examples of gtk_events_pending. It says:
This can be used to update the UI and invoke timeouts etc. while doing some time intensive computation.
Related
First post, so will try and be brief until need to add more. Ported an app from macOS to NI LabWindows/CVI, in "C", then to port to GTK3 and trying to grasp the updating GUI from external thread concept. I've read the gnome documentation and searched on here, and everywhere, but not finding similar usage, or not grasping the updating the GUI from separate thread. I have experimented with g_idle_add() as follows.
int main(int argc, char* argv[])
{
gtk_init(&argc, &argv); // init Gtk
gtk_start_button = GTK_WIDGET(gtk_builder_get_object(builder,"start_button"));
gtk_main();
return EXIT_SUCCESS;
}
void start_button_clicked_cb(GtkWidget *widget, gpointer data)
{
printf("\nStart Button Pressed\n");
run_tests();
}
void run_tests( void )
{
GThread *start_testing_thread;
start_testing_thread = g_thread_new("", &start_testing, NULL);
}
void *start_testing (void *data)
{
pause(5);
}
void pause( double pause_time)
{
char string[33];
while( (double)pause_time > (double)0 )
{
sprintf( string, "Pausing %02.1f", pause_time );
printf(string);
//test_name( string );
g_idle_add(test_name_gui, string);
g_usleep(100000); // uSecs for 100 mSecs
pause_time -= 0.1;
}
}
void test_name_gui(gpointer user_data)
{
GtkTextBuffer* buffer = gtk_text_buffer_new(NULL);
char temp[99];
int error = -1;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (gtktextview_test_name));
sprintf(temp,"\n%s gui\n",(char*)user_data);
printf(temp);
if(!g_utf8_validate(user_data,-1,NULL))
{
error = 3;
}
gtk_text_buffer_set_text (buffer, (char*)user_data, -1);
printf("\nTest Name gui\n");
g_object_unref(buffer);
return G_SOURCE_REMOVE;
}
In zetcode "Lines" code, I am trying to display the lines in real time as the mouse button is clicked. I then changed the clicked function to
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
gtk_widget_queue_draw(widget);
}
return TRUE;
}
I was thinking it would display the lines every time button 1 was clicked, but they are not being drawn on the window at all. What am i missing here?
The function that runs on draw, do_drawing(), contains this line at its end:
glob.count = 0;
so it clears the array after drawing them all, thus making it very hard to accumulate a large number of lines like you're trying to.
If you are following the Zetcode example, you need to change the do_drawing method. This works by drawing a point in real time with each click.
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);//Line colour
cairo_set_line_width(cr, 0.5);//Line width
cairo_translate(cr, -170, -170);//Shift where line
//i is starting point, i+1 is next mouse coordinate
int i;
for (i = 0; i < glob.count - 1; i++ ) {
cairo_move_to(cr, glob.coordx[i], glob.coordy[i]);
cairo_line_to(cr, glob.coordx[i+1], glob.coordy[i+1]);
printf("from x:%f, y:%f\t to: x:%f, y:%f\n",glob.coordx[i],glob.coordy[i], glob.coordx[i+1], glob.coordy[i+1]);
cairo_stroke(cr);
}
}
I have a big code of GTK2 in which I´m having troubles updating the value of an integer (in this case trigan, that its defined in the main body and callbacked to the two functions that are giving me this problem).
I intend to press the button RUN that calls the function RUN that starts displaying numbers in real time. Then, while text its running I will press STOP button that calls the function STOP, updating the value of trigan to 1.
Here is the piece of code in question:
void STOP(GtkWidget *widget, GObject *context_object_stp)
{
GtkEntry *trigan = g_object_get_data (context_object_stp, "trigan");
trigan=1;
}
void RUN(GtkWidget *widget, GObject *context_object)
{
GtkEntry *buffer= g_object_get_data (context_object, "buffer");
GtkEntry *wins = g_object_get_data (context_object, "wins");
GtkEntry *trigan = g_object_get_data (context_object, "trigan");
GtkWidget iter;
GtkTextIter iterscrll;
GtkTextMark *mark;
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &iterscrll, mark);
gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
trigan=0;
int i=0;
int k=0;
for (i=0; i<90; i=i+1)
{
while (trigan==1)
{
}
gchar * stuff = g_strdup_printf("%d"" [%d]\n", i, trigan);
/* Inserts buffer at position iter. */
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
/* Forcing. */
while (gtk_events_pending())
gtk_main_iteration();
/* Scrolls text_view the minimum distance such that mark is contained within the visible area of the widget. */
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), mark);
for (k=0; k<50000000; k=k+1)
{
k++;
}
k=0;
}
}
My logic say that whit this value of trigan=1 the
while (trigan==1)
{
}
should "stop" the function RUN, but it doesn't.
Help please!
yes, your assumption is correct but take a look at this extract of your code:
triga=0;
int i=0;
int k=0;
for (i=0; i<90; i=i+1)
{
while (triga==1)
{
}
as you see, triga is defined, assigned to 0 an never manipoulated in between before the while... so the condition while (triga==1) is false...
that is the reason..
I'm working on a project in C using gtk+ 2.0.
I must check if the user has pressed left click on a image. I thought to call a function when left click is pressed and to get the position of the mouse, but how can I do that?
I hope I can assume you know how to connect an event to a widget, but if not: Here's a previous answer of mine that demonstrates how to do just that.
g_signal_connect for right mouse click?
As you can see there the event is passed as a GdkEventButton * (event from now on). This struct has the member fields that you are after: event->x and event->y both are gdouble fields.
Anyway, #unwind is right. As the GTK docs clearly state:
GtkImage is a “no window” widget (has no GdkWindow of its own), so by default does not receive events. If you want to receive events on the image, such as button clicks, place the image inside a GtkEventBox, then connect to the event signals on the event box.
GtkImage is not the only "windowless" widget, BTW. GtkLabel, for example, requires a similar approach if you want to handle clicks on a label. Anyway: More info here.
The man page then continues with a full code example of how to handle clicks on a GtkImage widget. Just look for the title "Handling button press events on a GtkImage." for the full explanation, but here's the code in case the link breaks:
static gboolean
button_press_callback (GtkWidget *event_box,
GdkEventButton *event,
gpointer data)
{
g_print ("Event box clicked at coordinates %f,%f\n",
event->x, event->y);
// Returning TRUE means we handled the event, so the signal
// emission should be stopped (don’t call any further callbacks
// that may be connected). Return FALSE to continue invoking callbacks.
return TRUE;
}
static GtkWidget*
create_image (void)
{
GtkWidget *image;
GtkWidget *event_box;
image = gtk_image_new_from_file ("myfile.png");
event_box = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER (event_box), image);
g_signal_connect (G_OBJECT (event_box),
"button_press_event",
G_CALLBACK (button_press_callback),
image);
return image;
}
The problem is that the GtkImage widget which is used to show an image in GTK+ does not generate events.
It's a "nowindow" widget, meaning that it's a passive container, which is used to display information and not to interact with the user.
You can fix that by wrapping the image in a GtkEventBox, which will add event support.
In GTK you can use the button-pressed-event gtk widget to do this
In pure c, from Programming Simplified
#include<graphics.h>
#include<conio.h>
#include<stdio.h>
#include<dos.h>
int initmouse();
void showmouseptr();
void hidemouseptr();
void getmousepos(int*,int*,int*);
union REGS i, o;
main()
{
int gd = DETECT, gm, status, button, x, y, tempx, tempy;
char array[50];
initgraph(&gd,&gm,"C:\\TC\\BGI");
settextstyle(DEFAULT_FONT,0,2);
status = initmouse();
if ( status == 0 )
printf("Mouse support not available.\n");
else
{
showmouseptr();
getmousepos(&button,&x,&y);
tempx = x;
tempy = y;
while(!kbhit())
{
getmousepos(&button,&x,&y);
if( x == tempx && y == tempy )
{}
else
{
cleardevice();
sprintf(array,"X = %d, Y = %d",x,y);
outtext(array);
tempx = x;
tempy = y;
}
}
}
getch();
return 0;
}
int initmouse()
{
i.x.ax = 0;
int86(0X33,&i,&o);
return ( o.x.ax );
}
void showmouseptr()
{
i.x.ax = 1;
int86(0X33,&i,&o);
}
void getmousepos(int *button, int *x, int *y)
{
i.x.ax = 3;
int86(0X33,&i,&o);
*button = o.x.bx;
*x = o.x.cx;
*y = o.x.dx;
}
I create popup context menu with rightclick at runtime, from treeview, based on words in selected sentence. Code:
//---- inpropper ------------
gboolean
menu_RELEASE(GtkWidget *menu, gpointer *user_data)
{
printf("released at %s\n", (char*)user_data);
return FALSE;
}
//---------------------------
//---- propper [SOLVED] -----
gboolean
menu_RELEASE(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
gtk_entry_set_text(GTK_ENTRY(entry1), (char*)user_data);
gtk_widget_grab_focus(entry1);
return FALSE;
}
//--------------------------
GtkWidget *create_art_menu(GtkWidget *button)
{
char *ntext;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
if (gtk_tree_selection_get_selected(treesel, &model ,&iter))
{
gtk_tree_model_get(model, &iter, cNaziv, &ntext, -1);
GtkWidget *menu, *menu_item;
menu = gtk_menu_new();
char *sresult = NULL;
sresult = strtok(ntext, " ");
while(sresult != NULL)
{
if (strlen(sresult)>1)
{
menu_item = gtk_menu_item_new_with_label(sresult);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
g_signal_connect(G_OBJECT(menu_item), "button-release-event", G_CALLBACK(menu_RELEASE), (gpointer)sresult);
}
sresult = strtok(NULL, " ");
}
gtk_menu_attach_to_widget(GTK_MENU(menu), button, NULL);
gtk_widget_show_all(menu);
return menu;
}
return 0;
}
Signals are triggered and passes OK but I can't get string of clicked menu item in menu_RELEASE handler from user_data which I need for further action.
Q: How to get string of released menu item in menu_RELEASE handler based on showed code.
The reason is that the signature of callback which is connected to button-release-event is incorrect. The signature should be gboolean user_function(GtkWidget *widget,GdkEvent *event, gpointer user_data). Try changing gboolean menu_RELEASE(GtkWidget *menu, gpointer *user_data) to gboolean menu_RELEASE(GtkWidget *menu, GdkEvent *event, gpointer *user_data).
Alternatively, you can use g_signal_connect_swapped instead of g_signal_connect & change gboolean menu_RELEASE(GtkWidget *menu, gpointer *user_data) to gboolean menu_RELEASE(gpointer *user_data)
Additonally, be wary of what #Joachim Pileborg has already mention regarding strtok.
Hope this helps!
The result returned by the strtok function is a pointer to an internal static buffer, that will get overwritten on each call. If you want to save the result for use later, you have to create a duplicate (e.g. with the strdup function).
But watch out, doing this needs you to free the new string when done with it. for example if you remove the menu item, you need to free this buffer as well.