3
* GtkDrawingArea is a blank area where you can draw custom displays
6
* This demo has two drawing areas. The checkerboard area shows
7
* how you can just draw something; all you have to do is write
8
* a signal handler for expose_event, as shown here.
10
* The "scribble" area is a bit more advanced, and shows how to handle
11
* events such as button presses and mouse motion. Click the mouse
12
* and drag in the scribble area to draw squiggles. Resize the window
18
static GtkWidget *window = NULL;
19
/* Pixmap for scribble area, to store current scribbles */
20
static GdkPixmap *pixmap = NULL;
22
/* Create a new pixmap of the appropriate size to store our scribbles */
24
scribble_configure_event (GtkWidget *widget,
25
GdkEventConfigure *event,
29
g_object_unref (pixmap);
31
pixmap = gdk_pixmap_new (widget->window,
32
widget->allocation.width,
33
widget->allocation.height,
36
/* Initialize the pixmap to white */
37
gdk_draw_rectangle (pixmap,
38
widget->style->white_gc,
41
widget->allocation.width,
42
widget->allocation.height);
44
/* We've handled the configure event, no need for further processing. */
48
/* Redraw the screen from the pixmap */
50
scribble_expose_event (GtkWidget *widget,
51
GdkEventExpose *event,
54
/* We use the "foreground GC" for the widget since it already exists,
55
* but honestly any GC would work. The only thing to worry about
56
* is whether the GC has an inappropriate clip region set.
59
gdk_draw_drawable (widget->window,
60
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
62
/* Only copy the area that was exposed. */
63
event->area.x, event->area.y,
64
event->area.x, event->area.y,
65
event->area.width, event->area.height);
70
/* Draw a rectangle on the screen */
72
draw_brush (GtkWidget *widget,
76
GdkRectangle update_rect;
78
update_rect.x = x - 3;
79
update_rect.y = y - 3;
80
update_rect.width = 6;
81
update_rect.height = 6;
83
/* Paint to the pixmap, where we store our state */
84
gdk_draw_rectangle (pixmap,
85
widget->style->black_gc,
87
update_rect.x, update_rect.y,
88
update_rect.width, update_rect.height);
90
/* Now invalidate the affected region of the drawing area. */
91
gdk_window_invalidate_rect (widget->window,
97
scribble_button_press_event (GtkWidget *widget,
98
GdkEventButton *event,
102
return FALSE; /* paranoia check, in case we haven't gotten a configure event */
104
if (event->button == 1)
105
draw_brush (widget, event->x, event->y);
107
/* We've handled the event, stop processing */
112
scribble_motion_notify_event (GtkWidget *widget,
113
GdkEventMotion *event,
117
GdkModifierType state;
120
return FALSE; /* paranoia check, in case we haven't gotten a configure event */
122
/* This call is very important; it requests the next motion event.
123
* If you don't call gdk_window_get_pointer() you'll only get
124
* a single motion event. The reason is that we specified
125
* GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events().
126
* If we hadn't specified that, we could just use event->x, event->y
127
* as the pointer location. But we'd also get deluged in events.
128
* By requesting the next event as we handle the current one,
129
* we avoid getting a huge number of events faster than we
133
gdk_window_get_pointer (event->window, &x, &y, &state);
135
if (state & GDK_BUTTON1_MASK)
136
draw_brush (widget, x, y);
138
/* We've handled it, stop processing */
144
checkerboard_expose (GtkWidget *da,
145
GdkEventExpose *event,
148
gint i, j, xcount, ycount;
152
#define CHECK_SIZE 10
155
/* At the start of an expose handler, a clip region of event->area
156
* is set on the window, and event->area has been cleared to the
157
* widget's background color. The docs for
158
* gdk_window_begin_paint_region() give more details on how this
162
/* It would be a bit more efficient to keep these
163
* GC's around instead of recreating on each expose, but
164
* this is the lazy/slow way.
166
gc1 = gdk_gc_new (da->window);
170
gdk_gc_set_rgb_fg_color (gc1, &color);
172
gc2 = gdk_gc_new (da->window);
176
gdk_gc_set_rgb_fg_color (gc2, &color);
180
while (i < da->allocation.width)
183
ycount = xcount % 2; /* start with even/odd depending on row */
184
while (j < da->allocation.height)
193
/* If we're outside event->area, this will do nothing.
194
* It might be mildly more efficient if we handled
195
* the clipping ourselves, but again we're feeling lazy.
197
gdk_draw_rectangle (da->window,
204
j += CHECK_SIZE + SPACING;
208
i += CHECK_SIZE + SPACING;
212
g_object_unref (gc1);
213
g_object_unref (gc2);
215
/* return TRUE because we've handled this event, so no
216
* further processing is required.
227
g_object_unref (pixmap);
232
do_drawingarea (GtkWidget *do_widget)
241
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
242
gtk_window_set_screen (GTK_WINDOW (window),
243
gtk_widget_get_screen (do_widget));
244
gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
246
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
248
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
250
vbox = gtk_vbox_new (FALSE, 8);
251
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
252
gtk_container_add (GTK_CONTAINER (window), vbox);
255
* Create the checkerboard area
258
label = gtk_label_new (NULL);
259
gtk_label_set_markup (GTK_LABEL (label),
260
"<u>Checkerboard pattern</u>");
261
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
263
frame = gtk_frame_new (NULL);
264
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
265
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
267
da = gtk_drawing_area_new ();
268
/* set a minimum size */
269
gtk_widget_set_size_request (da, 100, 100);
271
gtk_container_add (GTK_CONTAINER (frame), da);
273
g_signal_connect (da, "expose_event",
274
G_CALLBACK (checkerboard_expose), NULL);
277
* Create the scribble area
280
label = gtk_label_new (NULL);
281
gtk_label_set_markup (GTK_LABEL (label),
282
"<u>Scribble area</u>");
283
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
285
frame = gtk_frame_new (NULL);
286
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
287
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
289
da = gtk_drawing_area_new ();
290
/* set a minimum size */
291
gtk_widget_set_size_request (da, 100, 100);
293
gtk_container_add (GTK_CONTAINER (frame), da);
295
/* Signals used to handle backing pixmap */
297
g_signal_connect (da, "expose_event",
298
G_CALLBACK (scribble_expose_event), NULL);
299
g_signal_connect (da,"configure_event",
300
G_CALLBACK (scribble_configure_event), NULL);
304
g_signal_connect (da, "motion_notify_event",
305
G_CALLBACK (scribble_motion_notify_event), NULL);
306
g_signal_connect (da, "button_press_event",
307
G_CALLBACK (scribble_button_press_event), NULL);
310
/* Ask to receive events the drawing area doesn't normally
313
gtk_widget_set_events (da, gtk_widget_get_events (da)
314
| GDK_LEAVE_NOTIFY_MASK
315
| GDK_BUTTON_PRESS_MASK
316
| GDK_POINTER_MOTION_MASK
317
| GDK_POINTER_MOTION_HINT_MASK);
321
if (!GTK_WIDGET_VISIBLE (window))
322
gtk_widget_show_all (window);
324
gtk_widget_destroy (window);