1#include <gtk/gtk.h>
2
3/* Surface to store current scribbles */
4static cairo_surface_t *surface = NULL;
5
6static void
7clear_surface (void)
8{
9 cairo_t *cr;
10
11 cr = cairo_create (target: surface);
12
13 cairo_set_source_rgb (cr, red: 1, green: 1, blue: 1);
14 cairo_paint (cr);
15
16 cairo_destroy (cr);
17}
18
19/* Create a new surface of the appropriate size to store our scribbles */
20static void
21resize_cb (GtkWidget *widget,
22 int width,
23 int height,
24 gpointer data)
25{
26 if (surface)
27 {
28 cairo_surface_destroy (surface);
29 surface = NULL;
30 }
31
32 if (gtk_native_get_surface (self: gtk_widget_get_native (widget)))
33 {
34 surface = gdk_surface_create_similar_surface (surface: gtk_native_get_surface (self: gtk_widget_get_native (widget)),
35 content: CAIRO_CONTENT_COLOR,
36 width: gtk_widget_get_width (widget),
37 height: gtk_widget_get_height (widget));
38
39 /* Initialize the surface to white */
40 clear_surface ();
41 }
42}
43
44/* Redraw the screen from the surface. Note that the draw
45 * callback receives a ready-to-be-used cairo_t that is already
46 * clipped to only draw the exposed areas of the widget
47 */
48static void
49draw_cb (GtkDrawingArea *drawing_area,
50 cairo_t *cr,
51 int width,
52 int height,
53 gpointer data)
54{
55 cairo_set_source_surface (cr, surface, x: 0, y: 0);
56 cairo_paint (cr);
57}
58
59/* Draw a rectangle on the surface at the given position */
60static void
61draw_brush (GtkWidget *widget,
62 double x,
63 double y)
64{
65 cairo_t *cr;
66
67 /* Paint to the surface, where we store our state */
68 cr = cairo_create (target: surface);
69
70 cairo_rectangle (cr, x: x - 3, y: y - 3, width: 6, height: 6);
71 cairo_fill (cr);
72
73 cairo_destroy (cr);
74
75 /* Now invalidate the drawing area. */
76 gtk_widget_queue_draw (widget);
77}
78
79static double start_x;
80static double start_y;
81
82static void
83drag_begin (GtkGestureDrag *gesture,
84 double x,
85 double y,
86 GtkWidget *area)
87{
88 start_x = x;
89 start_y = y;
90
91 draw_brush (widget: area, x, y);
92}
93
94static void
95drag_update (GtkGestureDrag *gesture,
96 double x,
97 double y,
98 GtkWidget *area)
99{
100 draw_brush (widget: area, x: start_x + x, y: start_y + y);
101}
102
103static void
104drag_end (GtkGestureDrag *gesture,
105 double x,
106 double y,
107 GtkWidget *area)
108{
109 draw_brush (widget: area, x: start_x + x, y: start_y + y);
110}
111
112static void
113pressed (GtkGestureClick *gesture,
114 int n_press,
115 double x,
116 double y,
117 GtkWidget *area)
118{
119 clear_surface ();
120 gtk_widget_queue_draw (widget: area);
121}
122
123static void
124close_window (void)
125{
126 if (surface)
127 cairo_surface_destroy (surface);
128}
129
130static void
131activate (GtkApplication *app,
132 gpointer user_data)
133{
134 GtkWidget *window;
135 GtkWidget *drawing_area;
136 GtkGesture *drag;
137 GtkGesture *press;
138
139 window = gtk_application_window_new (application: app);
140 gtk_window_set_title (GTK_WINDOW (window), title: "Drawing Area");
141
142 g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
143
144 drawing_area = gtk_drawing_area_new ();
145 /* set a minimum size */
146 gtk_widget_set_size_request (widget: drawing_area, width: 100, height: 100);
147
148 gtk_window_set_child (GTK_WINDOW (window), child: drawing_area);
149
150 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), draw_func: draw_cb, NULL, NULL);
151
152 g_signal_connect_after (drawing_area, "resize", G_CALLBACK (resize_cb), NULL);
153
154 drag = gtk_gesture_drag_new ();
155 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
156 gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (drag));
157 g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), drawing_area);
158 g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), drawing_area);
159 g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), drawing_area);
160
161 press = gtk_gesture_click_new ();
162 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (press), GDK_BUTTON_SECONDARY);
163 gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (press));
164
165 g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area);
166
167 gtk_widget_show (widget: window);
168}
169
170int
171main (int argc,
172 char **argv)
173{
174 GtkApplication *app;
175 int status;
176
177 app = gtk_application_new (application_id: "org.gtk.example", flags: G_APPLICATION_FLAGS_NONE);
178 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
179 status = g_application_run (G_APPLICATION (app), argc, argv);
180 g_object_unref (object: app);
181
182 return status;
183}
184

source code of gtk/examples/drawing.c