1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpcolor/gimpcolor.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "display-types.h"
27
28 #include "config/gimpdisplayconfig.h"
29
30 #include "widgets/gimpwidgets-utils.h"
31
32 #include "gimpcanvas.h"
33
34 #include "gimp-intl.h"
35
36
37 #define MAX_BATCH_SIZE 32000
38
39
40 enum
41 {
42 PROP_0,
43 PROP_CONFIG
44 };
45
46
47 /* local function prototypes */
48
49 static void gimp_canvas_set_property (GObject *object,
50 guint property_id,
51 const GValue *value,
52 GParamSpec *pspec);
53 static void gimp_canvas_get_property (GObject *object,
54 guint property_id,
55 GValue *value,
56 GParamSpec *pspec);
57
58 static void gimp_canvas_unrealize (GtkWidget *widget);
59 static void gimp_canvas_style_set (GtkWidget *widget,
60 GtkStyle *prev_style);
61 static gboolean gimp_canvas_focus_in_event (GtkWidget *widget,
62 GdkEventFocus *event);
63 static gboolean gimp_canvas_focus_out_event (GtkWidget *widget,
64 GdkEventFocus *event);
65 static gboolean gimp_canvas_focus (GtkWidget *widget,
66 GtkDirectionType direction);
67
68
G_DEFINE_TYPE(GimpCanvas,gimp_canvas,GIMP_TYPE_OVERLAY_BOX)69 G_DEFINE_TYPE (GimpCanvas, gimp_canvas, GIMP_TYPE_OVERLAY_BOX)
70
71 #define parent_class gimp_canvas_parent_class
72
73
74 static void
75 gimp_canvas_class_init (GimpCanvasClass *klass)
76 {
77 GObjectClass *object_class = G_OBJECT_CLASS (klass);
78 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
79
80 object_class->set_property = gimp_canvas_set_property;
81 object_class->get_property = gimp_canvas_get_property;
82
83 widget_class->unrealize = gimp_canvas_unrealize;
84 widget_class->style_set = gimp_canvas_style_set;
85 widget_class->focus_in_event = gimp_canvas_focus_in_event;
86 widget_class->focus_out_event = gimp_canvas_focus_out_event;
87 widget_class->focus = gimp_canvas_focus;
88
89 g_object_class_install_property (object_class, PROP_CONFIG,
90 g_param_spec_object ("config", NULL, NULL,
91 GIMP_TYPE_DISPLAY_CONFIG,
92 GIMP_PARAM_READWRITE |
93 G_PARAM_CONSTRUCT_ONLY));
94 }
95
96 static void
gimp_canvas_init(GimpCanvas * canvas)97 gimp_canvas_init (GimpCanvas *canvas)
98 {
99 GtkWidget *widget = GTK_WIDGET (canvas);
100
101 gtk_widget_set_can_focus (widget, TRUE);
102 gtk_widget_add_events (widget, GIMP_CANVAS_EVENT_MASK);
103 gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_ALL);
104 }
105
106 static void
gimp_canvas_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)107 gimp_canvas_set_property (GObject *object,
108 guint property_id,
109 const GValue *value,
110 GParamSpec *pspec)
111 {
112 GimpCanvas *canvas = GIMP_CANVAS (object);
113
114 switch (property_id)
115 {
116 case PROP_CONFIG:
117 canvas->config = g_value_get_object (value); /* don't dup */
118 break;
119
120 default:
121 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
122 break;
123 }
124 }
125
126 static void
gimp_canvas_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)127 gimp_canvas_get_property (GObject *object,
128 guint property_id,
129 GValue *value,
130 GParamSpec *pspec)
131 {
132 GimpCanvas *canvas = GIMP_CANVAS (object);
133
134 switch (property_id)
135 {
136 case PROP_CONFIG:
137 g_value_set_object (value, canvas->config);
138 break;
139
140 default:
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
142 break;
143 }
144 }
145
146 static void
gimp_canvas_unrealize(GtkWidget * widget)147 gimp_canvas_unrealize (GtkWidget *widget)
148 {
149 GimpCanvas *canvas = GIMP_CANVAS (widget);
150
151 g_clear_object (&canvas->layout);
152
153 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
154 }
155
156 static void
gimp_canvas_style_set(GtkWidget * widget,GtkStyle * prev_style)157 gimp_canvas_style_set (GtkWidget *widget,
158 GtkStyle *prev_style)
159 {
160 GimpCanvas *canvas = GIMP_CANVAS (widget);
161
162 GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
163
164 g_clear_object (&canvas->layout);
165 }
166
167 static gboolean
gimp_canvas_focus_in_event(GtkWidget * widget,GdkEventFocus * event)168 gimp_canvas_focus_in_event (GtkWidget *widget,
169 GdkEventFocus *event)
170 {
171 /* don't allow the default impl to invalidate the whole widget,
172 * we don't draw a focus indicator anyway.
173 */
174 return FALSE;
175 }
176
177 static gboolean
gimp_canvas_focus_out_event(GtkWidget * widget,GdkEventFocus * event)178 gimp_canvas_focus_out_event (GtkWidget *widget,
179 GdkEventFocus *event)
180 {
181 /* see focus-in-event
182 */
183 return FALSE;
184 }
185
186 static gboolean
gimp_canvas_focus(GtkWidget * widget,GtkDirectionType direction)187 gimp_canvas_focus (GtkWidget *widget,
188 GtkDirectionType direction)
189 {
190 GtkWidget *focus = gtk_container_get_focus_child (GTK_CONTAINER (widget));
191
192 /* override GtkContainer's focus() implementation which would always
193 * give focus to the canvas because it is focussable. Instead, try
194 * navigating in the focused overlay child first, and use
195 * GtkContainer's default implementation only if that fails (which
196 * happens when focus navigation leaves the overlay child).
197 */
198
199 if (focus && gtk_widget_child_focus (focus, direction))
200 return TRUE;
201
202 return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
203 }
204
205
206 /* public functions */
207
208 /**
209 * gimp_canvas_new:
210 *
211 * Creates a new #GimpCanvas widget.
212 *
213 * The #GimpCanvas widget is a #GtkDrawingArea abstraction. It manages
214 * a set of graphic contexts for drawing on a GIMP display. If you
215 * draw using a #GimpCanvasStyle, #GimpCanvas makes sure that the
216 * associated #GdkGC is created. All drawing on the canvas needs to
217 * happen by means of the #GimpCanvas drawing functions. Besides from
218 * not needing a #GdkGC pointer, the #GimpCanvas drawing functions
219 * look and work like their #GdkDrawable counterparts. #GimpCanvas
220 * gracefully handles attempts to draw on the unrealized widget.
221 *
222 * Return value: a new #GimpCanvas widget
223 **/
224 GtkWidget *
gimp_canvas_new(GimpDisplayConfig * config)225 gimp_canvas_new (GimpDisplayConfig *config)
226 {
227 g_return_val_if_fail (GIMP_IS_DISPLAY_CONFIG (config), NULL);
228
229 return g_object_new (GIMP_TYPE_CANVAS,
230 "name", "gimp-canvas",
231 "config", config,
232 NULL);
233 }
234
235 /**
236 * gimp_canvas_get_layout:
237 * @canvas: a #GimpCanvas widget
238 * @format: a standard printf() format string.
239 * @Varargs: the parameters to insert into the format string.
240 *
241 * Returns a layout which can be used for
242 * pango_cairo_show_layout(). The layout belongs to the canvas and
243 * should not be freed, not should a pointer to it be kept around
244 * after drawing.
245 *
246 * Returns: a #PangoLayout owned by the canvas.
247 **/
248 PangoLayout *
gimp_canvas_get_layout(GimpCanvas * canvas,const gchar * format,...)249 gimp_canvas_get_layout (GimpCanvas *canvas,
250 const gchar *format,
251 ...)
252 {
253 va_list args;
254 gchar *text;
255
256 if (! canvas->layout)
257 canvas->layout = gtk_widget_create_pango_layout (GTK_WIDGET (canvas),
258 NULL);
259
260 va_start (args, format);
261 text = g_strdup_vprintf (format, args);
262 va_end (args);
263
264 pango_layout_set_text (canvas->layout, text, -1);
265 g_free (text);
266
267 return canvas->layout;
268 }
269
270 /**
271 * gimp_canvas_set_bg_color:
272 * @canvas: a #GimpCanvas widget
273 * @color: a color in #GimpRGB format
274 *
275 * Sets the background color of the canvas's window. This
276 * is the color the canvas is set to if it is cleared.
277 **/
278 void
gimp_canvas_set_bg_color(GimpCanvas * canvas,GimpRGB * color)279 gimp_canvas_set_bg_color (GimpCanvas *canvas,
280 GimpRGB *color)
281 {
282 GtkWidget *widget = GTK_WIDGET (canvas);
283 GdkColormap *colormap;
284 GdkColor gdk_color;
285
286 if (! gtk_widget_get_realized (widget))
287 return;
288
289 gimp_rgb_get_gdk_color (color, &gdk_color);
290
291 colormap = gdk_drawable_get_colormap (gtk_widget_get_window (widget));
292 g_return_if_fail (colormap != NULL);
293 gdk_colormap_alloc_color (colormap, &gdk_color, FALSE, TRUE);
294
295 gdk_window_set_background (gtk_widget_get_window (widget), &gdk_color);
296
297 gtk_widget_queue_draw (GTK_WIDGET (canvas));
298 }
299