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);
}
}
Related
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.
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'm trying to incorporate vim like functionality in a text editor I am creating in gtk+ 2.0 and gtksourceview 2.0. I have it working except when I press "i" to enter insert mode it enters this mode properly, but then it types an "i" in the text buffer. Here is my keypress function which is setup to enter command mode (leave insert mode) when the esc key is hit, and as I said before enter insert mode when the i key is pressed:
gboolean on_key_press_win_main (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
switch (event->keyval)
{
case GDK_i:
if (event->state & GDK_CONTROL_MASK)
{
printf("key pressed: %s\n", "ctrl + i");
}
else
{
GtkTextBuffer *tbuffer;
GtkTextView *text_view;
int page = 0;
gchar *msg;
gint row, col;
GtkTextIter iter;
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
text_view = GTK_TEXT_VIEW(txtinput[notebookPages[page]]);
tbuffer = gtk_text_view_get_buffer (text_view);
if (insert_mode == 0)
{
insert_mode = 1;
command_mode = 0;
/* update statusbar */
gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 0);
gtk_text_buffer_get_iter_at_mark(tbuffer, &iter, gtk_text_buffer_get_insert(tbuffer));
row = gtk_text_iter_get_line(&iter);
col = gtk_text_iter_get_line_offset(&iter);
msg = g_strdup_printf("INSERT\t\t Col %d Ln %d", col+1, row+1);
gtk_statusbar_push(GTK_STATUSBAR(statusbar), 0, msg);
gtk_text_view_set_editable (text_view, TRUE);
}
}
break;
/* esc key */
case 65307:
{
GtkTextBuffer *tbuffer;
GtkTextView *text_view;
int page = 0;
gchar *msg;
gint row, col;
GtkTextIter iter;
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
text_view = GTK_TEXT_VIEW(txtinput[notebookPages[page]]);
tbuffer = gtk_text_view_get_buffer (text_view);
insert_mode = 0;
command_mode = 1;
gtk_text_view_set_editable (text_view, FALSE);
/* update statusbar */
gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 0);
gtk_text_buffer_get_iter_at_mark(tbuffer, &iter, gtk_text_buffer_get_insert(tbuffer));
row = gtk_text_iter_get_line(&iter);
col = gtk_text_iter_get_line_offset(&iter);
msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);
gtk_statusbar_push(GTK_STATUSBAR(statusbar), 0, msg);
}
break;
default:
return FALSE;
}
return FALSE;
}
As you can see gtk_text_view_set_editable (text_view, FALSE) is set when entering command mode, and gtk_text_view_set_editable (text_view, TRUE) is set when entering insert mode. However, when entering insert mode the text_view is set editable before the keystroke registers in the buffer even if it is the last command in the keypress case. How can I keep the i from being placed in the text buffer when entering insert mode?
Return TRUE from the event handler instead of FALSE to block any further processing of the event. Event handlers work like a filter, you filter out the keystrokes that you don't want to pass on to the textview.
PS. Don't use constants like 65307, use GDK_KEY_Escape or whatever it is.
Wouldn't you know it, as soon as I finished writing this question a viable option pops into my head. This is probably why the key_release_event was created. Worked like a charm.
I've been trying to flip surfaces and have been successful if I'm only flipping a single surface (the same surface I got back from SDL_SetVideoMode). If I try to flip the surface I get back from SDL_DisplayFormat, nothing happens. I've attached demo code that demonstrates my problem:
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *mysurface1;
SDL_Surface *mysurface2;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
mysurface1 = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface1->pixels + i*mysurface1->pitch + i;
*pxl = 100; // Red Line
}
SDL_Flip(mysurface1); // Works, we see a red line
sleep(5);
printf("Sleeping for 5...\n");
mysurface2 = SDL_DisplayFormat(mysurface1);
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface2->pixels + i*mysurface2->pitch + i;
*pxl = 255; // White line
}
SDL_Flip(mysurface2); // White line doesnt appear
printf("Done... No white line\n");
sleep(10);
}
Has anyone ever seen this before? Again, I think I tracked it down to surfaces that wont display if its a surface I got back from SDL_DisplayFormat. If I do it on the surface I get back from SDL_SetVideoMode, then I see the red line and everything works fine.
You can only flip the main display surface (the one created with SDL_SetVideoMode). In order to make your other surface visible, you need to blit it onto the main surface. Lookup SDL_BlitSurface for details on how to do that.
Pass the screen to the SDL_Flip function. The flip function modifies the value of screen->pixels so that it points to the surface that isn't visible on the screen.
However, this is only applicable to video devices such as SVGA and DGA. On X11, calling SDL_Flip(screen) is equivalent to calling SDL_UpdateRect(screen, 0, 0, 0, 0).
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *screen;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
printf("Drawing the red line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 100; // Red Line
}
printf("Flip screens\n");
SDL_Flip(screen); // Display the red line
printf("Drawing the white line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 255; // White line
}
sleep(3);
printf("Flip screens\n");
SDL_Flip(screen); // Display the white line
sleep(10);
}
On my Linux notebook, this prints:
Drawing the red line ...
screen->pixels = 0xb6c8c008
Flip screens
Drawing the white line ...
screen->pixels = 0xb6c8c008
Flip screens
The value of screen->pixels is the same, but this is only because on X11 the flip operation is a no-operation. On a video device such as SVGA or DGA, the two values would be different.
First, it seems SDL_Flip() only works on surfaces that correspond to the screen or a window, like those created by SDL_SetVideoMode(). Your other surface is off-screen; it doesn't make much sense to double-buffer it (or flip it), and it most likely isn't double-buffered anyway. Being an off screen surface, it won't appear until you blit it to your display surface with SDL_BlitSurface() or a similar function -- then, the changes will be visible next time you flip the display surface.
Essentially, mysurface2 isn't actually on your display until you put it there, by blitting it onto a surface that is on your display. If you replace the following:
SDL_Flip(mysurface2); // White line doesnt appear
With this:
SDL_BlitSurface(mysurface2,NULL,mysurface1,NULL);
SDL_Flip(mysurface1);
...then your code will probably work as you expect.