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