1 #include <gtk/gtk.h>
2
3 /* Surface to store current scribbles */
4 static cairo_surface_t *surface = NULL;
5
6 static void
clear_surface(void)7 clear_surface (void)
8 {
9 cairo_t *cr;
10
11 cr = cairo_create (surface);
12
13 cairo_set_source_rgb (cr, 1, 1, 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 */
20 static void
resize_cb(GtkWidget * widget,int width,int height,gpointer data)21 resize_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 (gtk_widget_get_native (widget)))
33 {
34 surface = gdk_surface_create_similar_surface (gtk_native_get_surface (gtk_widget_get_native (widget)),
35 CAIRO_CONTENT_COLOR,
36 gtk_widget_get_width (widget),
37 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 */
48 static void
draw_cb(GtkDrawingArea * drawing_area,cairo_t * cr,int width,int height,gpointer data)49 draw_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, 0, 0);
56 cairo_paint (cr);
57 }
58
59 /* Draw a rectangle on the surface at the given position */
60 static void
draw_brush(GtkWidget * widget,double x,double y)61 draw_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 (surface);
69
70 cairo_rectangle (cr, x - 3, y - 3, 6, 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
79 static double start_x;
80 static double start_y;
81
82 static void
drag_begin(GtkGestureDrag * gesture,double x,double y,GtkWidget * area)83 drag_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 (area, x, y);
92 }
93
94 static void
drag_update(GtkGestureDrag * gesture,double x,double y,GtkWidget * area)95 drag_update (GtkGestureDrag *gesture,
96 double x,
97 double y,
98 GtkWidget *area)
99 {
100 draw_brush (area, start_x + x, start_y + y);
101 }
102
103 static void
drag_end(GtkGestureDrag * gesture,double x,double y,GtkWidget * area)104 drag_end (GtkGestureDrag *gesture,
105 double x,
106 double y,
107 GtkWidget *area)
108 {
109 draw_brush (area, start_x + x, start_y + y);
110 }
111
112 static void
pressed(GtkGestureClick * gesture,int n_press,double x,double y,GtkWidget * area)113 pressed (GtkGestureClick *gesture,
114 int n_press,
115 double x,
116 double y,
117 GtkWidget *area)
118 {
119 clear_surface ();
120 gtk_widget_queue_draw (area);
121 }
122
123 static void
close_window(void)124 close_window (void)
125 {
126 if (surface)
127 cairo_surface_destroy (surface);
128 }
129
130 static void
activate(GtkApplication * app,gpointer user_data)131 activate (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 (app);
140 gtk_window_set_title (GTK_WINDOW (window), "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 (drawing_area, 100, 100);
147
148 gtk_window_set_child (GTK_WINDOW (window), drawing_area);
149
150 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), 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 (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 (drawing_area, GTK_EVENT_CONTROLLER (press));
164
165 g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area);
166
167 gtk_widget_show (window);
168 }
169
170 int
main(int argc,char ** argv)171 main (int argc,
172 char **argv)
173 {
174 GtkApplication *app;
175 int status;
176
177 app = gtk_application_new ("org.gtk.example", 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 (app);
181
182 return status;
183 }
184