GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Help needed on "expose event"

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming
Author Message
aliercan
Familiar Face


Joined: 05 Sep 2008
Posts: 5

PostPosted: Fri Sep 05, 2008 6:17 pm    Post subject: Help needed on "expose event" Reply with quote

Hi,

I am a GTK newbee and I will appreciate any help on my following question about expose events.

I have an application where I use the GtkLayout structure to put images to fixed positions on the layout and draw lines between them. I also want to drag these images to different positions and redraw the lines when something is dragged.

I store the information about the lines in a linked list, and whenever and expose event is emitted, the callback function calls "draw_lines()" and the lines are updated. This works fine say whenever I resize the window.

However, when I drag an image, the expose event structure contains only the rectangle that contains the dragged image, and therefore redraws the portions of the lines that fall inside that rectangle. However, as the lines span all the way to the other images, this is not I want. I want the whole window to be redrawn for proper display of the lines. As I said, when I resize the window or minimize and maximize it, the whole window is updated and lines are drawn properly. I want this whole window update behavior for all expose events.

Is there a way to do this? I tried the following but id didn't work (in the main after gtk_widget_show (window); Here, area is a GtkLayout that generates the expose events and is contained in the window) :
Code: (C)
1
2
3
4
5
6
GdkRectangle *rect = (GdkRectangle*)malloc(sizeof(GdkRectangle));
rect->x = 0;
rect->y = 0;
rect->width = area->allocation.width;
rect->height = area->allocation.height;
gdk_window_invalidate_rect(GTK_LAYOUT(area)->bin_window,rect,FALSE);


I also tried using window for the first argument and TRUE for the last argument (and combinations of these) and none worked. Can anybody help?

Thank you very much in advance,

Ali.
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 568
Location: Falun, WI USA

PostPosted: Fri Sep 05, 2008 7:05 pm    Post subject: Reply with quote

calling gdk_window_invalidate_rect once after showing the window won't help you for any successive expose events,
you'd need to do it in your expose-event callback.

can you post your code? it would be a great help if you can because it's kind of hard to follow what's going on without any code.
thanks...
Back to top
aliercan
Familiar Face


Joined: 05 Sep 2008
Posts: 5

PostPosted: Fri Sep 05, 2008 8:02 pm    Post subject: Reply with quote

Thank you very much! It works! I basically just put the above code inside the callback function. If anyone is still interested in the entire code, I can post it as well.

Ali.
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 568
Location: Falun, WI USA

PostPosted: Fri Sep 05, 2008 8:09 pm    Post subject: Reply with quote

I would be interested in seeing the code...
Back to top
aliercan
Familiar Face


Joined: 05 Sep 2008
Posts: 5

PostPosted: Fri Sep 05, 2008 8:32 pm    Post subject: Reply with quote

Well I am still working on it so some parts are missing. This is supposed to be a graphical interface for a networking demo. Many devices will send packets to a laptop and each packet will have the trace of the devices they went through. The interface will run at the end laptop, and it will show the connectivity in the network by drawing lines between different devices.

Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#include <gtk/gtk.h>
#include <stdlib.h>
#include <time.h>

#define XSIZE  800
#define YSIZE  600
#define SUCCESS 0
#define TITLE "Connectivity Broker Demo"
#define N800 "n800s.xpm"
#define ROUTER "router_s.xpm"
#define LAPTOP "t61s.xpm"
#define DUMMY "dummy.xpm"
#define nN800 3
#define nLAPTOP 2
#define nROUTER 1
#define LINEW 3
#define WIRED 0
#define WIFI 1
#define PERIOD 200 //ms
#define LABELS "labels.txt"
#define MAX_LAB_SIZE 200

//#define LAYOUT 1

gint TOKEN=-1; //global var. An object claims this token if it is being moved, preventing others from being moved at the same time.
gint TIMEOUT_STARTED=FALSE;
gint TTAG;

struct point_t {
  gint x;
  gint y;
};
struct box_t {
  struct point_t topleft;
  struct point_t botright;
  gint width;
  gint height;
};

struct line_t {
  guint  begin; // index of the object that line begins
 
guint  end;
  gint type; // WIRED WIFI BLUETOOTH ...
};

struct cb_object {
  gint id;
  GtkWidget* label;
  GtkWidget *image; // The image of the object
 
struct box_t dims;
  struct point_t center;
  GtkWidget *area; // The area that we put the object to
};
int num_objs=0;

struct point_t where_to;

GList* lines = NULL; // the linked list of data for lines
GList* objs = NULL; //the linked list of data for objects

GdkGC* line_gc;
GdkGCValues line_gv;

static gint  obj_eq_id(struct cb_object* obj, gint *id) {
  return (obj->id == *id ? 0 : -1);
}

static void draw_line(struct line_t *line, GtkWidget* area) {
  gint x1, y1, x2, y2;
  /*
  x1 = objs[line->begin]->center.x;
  y1 = objs[line->begin]->center.y;
  x2 = objs[line->end]->center.x;
  y2 = objs[line->end]->center.y;
  */
 
GList* ii = g_list_find_custom(objs,&(line->begin),obj_eq_id);
  struct cb_object* obj = ii->data;
  //struct cb_object *obj = (struct cb_object*)g_list_nth_data(objs,line->begin);
 
x1 = obj->center.x;
  y1 = obj->center.y;
  ii = g_list_find_custom(objs,&(line->end),obj_eq_id);
  obj = ii->data;
  //obj = g_list_nth_data(objs,line->end);
 
x2 = obj->center.x;
  y2 = obj->center.y;
 
  switch (line->type) {
  case WIRED:
   
gdk_gc_set_line_attributes(line_gc,LINEW,GDK_LINE_SOLID,GDK_CAP_ROUND,GDK_JOIN_ROUND);
    break;
  case WIFI:
   
gdk_gc_set_line_attributes(line_gc,LINEW,GDK_LINE_ON_OFF_DASH
                ,GDK_CAP_ROUND,GDK_JOIN_ROUND);
    break;
  default:
    gdk_gc_set_line_attributes(line_gc,LINEW,GDK_LINE_SOLID,GDK_CAP_ROUND,GDK_JOIN_ROUND);
    break;
  }
  gdk_draw_line(GTK_LAYOUT(area)->bin_window,line_gc,x1,y1,x2,y2);
}
 
static void draw_lines(GtkWidget* area) {
  g_list_foreach(lines,draw_line,area);
}



/* Initialize one object from file name*/
static void init_obj(gchar *fname, GtkWidget *area, FILE* fd) {
  char lab[MAX_LAB_SIZE];
  struct cb_object *obj = (struct cb_object*) malloc(sizeof(struct cb_object));
  GtkWidget *image = gtk_image_new_from_file(fname);
  gint w = image->requisition.width;
  gint h = image->requisition.height;
  gint W = area->allocation.width;
  gint H = area->allocation.height;
  fgets(lab,MAX_LAB_SIZE,fd);
 
  int id;
  sscanf(lab,"%d",&id);
  char* r = strchr(lab,' ');
  r++;
  obj->label = gtk_label_new(r);
  obj->id = id;
  num_objs++;
  obj->dims.width = w;
  obj->dims.height = h;
  obj->dims.topleft.x = rand()%(W-w);
  obj->dims.topleft.y = rand()%(H-h);
  obj->dims.botright.x = obj->dims.topleft.x + w;
  obj->dims.botright.y = obj->dims.topleft.y + h;
  obj->center.x = obj->dims.topleft.x + w/2;
  obj->center.y = obj->dims.topleft.y + h/2;
  obj->area = area;
  obj->image = image;
  objs = g_list_append(objs,obj);

/* init all objs */
static void init_all(GtkWidget *area) {
  int ii;
  FILE* fd = fopen(LABELS,"r");
  for (ii=0;ii<nN800;ii++) {
    init_obj(N800,area,fd);
  }
  for (ii=0;ii<nROUTER;ii++) {
    init_obj(ROUTER,area,fd);
  }
  for (ii=0;ii<nLAPTOP;ii++) {
    init_obj(LAPTOP,area,fd);
  }
  fclose(fd);
}

static void put_obj(struct cb_object *obj, GtkWidget *area){
   gtk_layout_put(GTK_LAYOUT(area), obj->image, obj->dims.topleft.x, obj->dims.topleft.y);
   gtk_layout_put(GTK_LAYOUT(area), obj->label, obj->dims.topleft.x, obj->dims.botright.y+5);
   gtk_widget_show(obj->image);
   gtk_widget_show(obj->label);

static void put_objects(GtkWidget* area) {
  g_list_foreach(objs,put_obj,area);
}

static gboolean is_in_box(gint x, gint y, struct box_t *box) {
  //g_print("point: x: %d, y: %d\n",x,y);
 
return ((x <= box->botright.x) && (x >= box->topleft.x) &&
      (y <= box->botright.y) && (y >= box->topleft.y));
}

static void move_obj(struct cb_object *obj, GtkWidget *area){
  if (((TOKEN==-1) || (TOKEN==obj->id)) && is_in_box(where_to.x,where_to.y,&(obj->dims))) {
    if (TOKEN==-1) TOKEN = obj->id;
    obj->dims.topleft.x =  where_to.x-obj->dims.width/2;
    obj->dims.topleft.y = where_to.y-obj->dims.height/2;
    obj->dims.botright.x = where_to.x + obj->dims.width/2;
    obj->dims.botright.y = where_to.y + obj->dims.height/2;
    obj->center.x = where_to.x;
    obj->center.y = where_to.y;
    gtk_layout_move(GTK_LAYOUT(area), obj->image, obj->dims.topleft.x, obj->dims.topleft.y);
    gtk_layout_move(GTK_LAYOUT(area), obj->label, obj->dims.topleft.x, obj->dims.botright.y+5);
  }



static void update(GtkWidget *area) {
  g_print("Timeout! %d\n", TTAG);
  //draw_lines(area);
}


static gboolean expose_event( GtkWidget *widget, GdkEventExpose *event )
{
  g_print("expose event!!\n");
 // we want all of the drawable area to be updated at each expose event.
  // the code below doesn't work
 
GdkRectangle *rect = (GdkRectangle*)malloc(sizeof(GdkRectangle));
  rect->x = 0;
  rect->y = 0;
  rect->width = widget->allocation.width;
  rect->height = widget->allocation.height;
  gdk_window_invalidate_rect(GTK_LAYOUT(widget)->bin_window,rect,FALSE);   

  draw_lines(widget);
  free(rect);
  return FALSE;
}

static void free_image(struct cb_object *obj, gpointer data) {
  free(obj->image);
}
static gboolean close_application( GtkWidget *widget, GdkEvent *event, gpointer data )
{
  // to do: free the window, boxes, etc.
  //g_list_foreach(objs,free_image,NULL);
  //g_list_free(objs);
  //g_list_free(lines);
  //free(line_gc);
 
gtk_main_quit ();
  return FALSE;
}
static gboolean button_press_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) {
  g_print("Button pressed inside area!\n");
  g_print("X: %d, Y: %d\n",(gint)event->x,(gint)event->y);
  return TRUE;
}

static gboolean button_release_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) {
  g_print("button release!\n");
  //draw_lines(widget);
 
TOKEN = -1;
  return TRUE;
}
static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) {
  //g_print("motion with button 1!\n");
 
gint x, y;
  GdkModifierType state;
  if (event->is_hint)
    gdk_window_get_pointer (event->window, &x, &y, &state);
  else
   
{
      x = event->x;
      y = event->y;
      state = event->state;
    }
   
  if (state && GDK_BUTTON1_MASK) {
    where_to.x = x;
    where_to.y = y;
    g_list_foreach(objs,move_obj,widget);
  }

  return TRUE;
}

static gboolean stopVisual(GtkWidget *widget, gpointer data) {
  //g_print("button pressed!\n");
 
if (TIMEOUT_STARTED)
    g_source_remove (TTAG);
  TIMEOUT_STARTED = FALSE;
  return TRUE;
}
static gboolean startVisual(GtkWidget *widget, GtkWidget* area) {
  //g_print("button pressed!\n");
 
stopVisual(widget,NULL);
  TIMEOUT_STARTED = TRUE;
  TTAG = g_timeout_add(PERIOD,update,area);
  return TRUE;
}

/* The main routine */
int main( int   argc, char *argv[]) {
 
  GtkWidget *window, *vbox, *hbox, *button, *area;

  /* Initialize GTK and create the main window */
 
gtk_init (&argc, &argv);
  srand (time(NULL));
 

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
  gtk_window_set_title(GTK_WINDOW (window), TITLE);
  gtk_window_set_default_size (GTK_WINDOW (window), XSIZE, YSIZE);

 

  area = gtk_layout_new(NULL,NULL);
  gtk_widget_set_events (area, GDK_EXPOSURE_MASK
             | GDK_BUTTON_PRESS_MASK
             | GDK_BUTTON_RELEASE_MASK
             | GDK_BUTTON1_MOTION_MASK);
  gtk_widget_show (area);

  g_signal_connect (G_OBJECT (window), "delete_event",
            G_CALLBACK (close_application), NULL);   
  gtk_signal_connect(GTK_OBJECT (area), "button_press_event",
             (GtkSignalFunc) button_press_event, NULL);
  gtk_signal_connect(GTK_OBJECT (area), "button_release_event",
             (GtkSignalFunc) button_release_event, NULL);
  gtk_signal_connect(GTK_OBJECT (area), "motion_notify_event",
             (GtkSignalFunc) motion_notify_event, NULL);
  gtk_signal_connect (GTK_OBJECT (area), "expose_event",
              (GtkSignalFunc) expose_event, NULL);
 
 // buttons
 
vbox = gtk_vbox_new(FALSE,0);
  gtk_widget_show(vbox);
  gtk_container_add(GTK_CONTAINER(window),vbox);
  gtk_box_pack_start(GTK_BOX(vbox),area,TRUE,TRUE,0);
  GtkWidget *separator = gtk_hseparator_new ();
  gtk_widget_show(separator);
  gtk_box_pack_start(GTK_BOX(vbox),separator,FALSE,TRUE,5);
  hbox = gtk_hbox_new(TRUE,0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
  button = gtk_button_new_with_label ("Start Visualization");
  g_signal_connect (G_OBJECT (button), "clicked",
            G_CALLBACK (startVisual), area);
  gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,FALSE,0);
  gtk_widget_show (button);
  button = gtk_button_new_with_label ("Stop Visualization");
  g_signal_connect (G_OBJECT (button), "clicked",
            G_CALLBACK (stopVisual), NULL);
  gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,FALSE,0);
  gtk_widget_show (button);
  button = gtk_button_new_with_label ("Quit");
  g_signal_connect (G_OBJECT (button), "clicked",
            G_CALLBACK (close_application), NULL);
  gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,FALSE,0);
  gtk_widget_show (button);
  gtk_widget_show (window);
  gtk_layout_set_size(GTK_LAYOUT(area),XSIZE,YSIZE);
 

 

  init_all(area);
  /* for test, put a line between the first 2 maemos */                                     
 
struct line_t *line = (struct line_t*)malloc(sizeof(struct line_t));
  line->begin = 0;
  line->end = 1;
  line->type = WIFI;
  lines = g_list_append(lines,line);
 
  line = (struct line_t*)malloc(sizeof(struct line_t));
  line->begin = 1;
  line->end = 4;
  line->type = WIRED;
  lines = g_list_append(lines,line);
 
  put_objects(area);
 
  gdk_gc_get_values(area->style->black_gc,&line_gv);
  line_gc = gdk_gc_new_with_values(GTK_LAYOUT(area)->bin_window,&line_gv,
                   GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE |
                   GDK_GC_CAP_STYLE | GDK_GC_JOIN_STYLE | GDK_GC_FOREGROUND);
 

   gtk_main ();

  return SUCCESS;
}
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 568
Location: Falun, WI USA

PostPosted: Fri Sep 05, 2008 8:58 pm    Post subject: Reply with quote

can you provide a sample "labels.txt" file? right now the program crashes because init_all opens "labels.txt" without any NULL check
and since I don't have a "labels.txt" file, it segfaults.
thanks...
Back to top
aliercan
Familiar Face


Joined: 05 Sep 2008
Posts: 5

PostPosted: Fri Sep 05, 2008 11:37 pm    Post subject: Reply with quote

Here is what I use for labels.txt:

1 Ali's N800
2 Alvaro's N800
3 Jan's N800
0 Base Station
4 Arash's Laptop
5 Pavan's Laptop

The xpm files that I used are:

n800s.xpm:
[img]http://www.eecs.berkeley.edu/~aliercan/tmp/n800s.xpm[/img]
t61s.xpm
[img]http://www.eecs.berkeley.edu/~aliercan/tmp/t61s.xpm[/img]
router_s.xpm:
[img]http://www.eecs.berkeley.edu/~aliercan/tmp/router_s.xpm[/img]
Back to top
aliercan
Familiar Face


Joined: 05 Sep 2008
Posts: 5

PostPosted: Sat Sep 06, 2008 2:22 am    Post subject: Reply with quote

By the way, sorry about some of the comments in the above code. I keep changing things and forget to change the comments. Therefore, some comments don't make sense.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP