1 /* $Id: canvas.c,v 1.6 2005/01/07 02:50:52 meffie Exp $
2  *
3  * GNU Paint
4  * Copyright 2000-2003, 2007  Li-Cheng (Andy) Tai
5  *
6  * Authors: Li-Cheng (Andy) Tai <atai@gnu.org>
7  *          Michael A. Meffie III <meffiem@neo.rr.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 3
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be
15  * useful, but WITHOUT ANY WARRANTY; without even the implied
16  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
17  * PURPOSE. See the GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <gtk/gtk.h>
30 #include "debug.h"
31 #include "canvas.h"
32 #include "util.h"
33 #include "gtkscrollframe.h"
34 #include "image.h"
35 #include "image_processing.h"
36 #include "paste.h"
37 #include "selection.h"
38 #include "text.h"
39 #include "global.h"
40 
41 #define GPAINT_CLIPBOARD_KEY "gpaint-clipboard"
42 
43 /* Single clipboard to share selections between canvases. */
44 static gpaint_clipboard *clipboard = NULL;
45 
46 /* macros to cast user_data in the callbacks */
47 #define CANVAS(user_data)      ((gpaint_canvas*)(user_data))
48 #define ACTIVE_TOOL(user_data) (((gpaint_canvas*)(user_data))->active_tool)
49 #define DRAWING(user_data)     (((gpaint_canvas*)(user_data))->drawing)
50 
51 /* gobject canvas */
52 #define GPAINT_TYPE_CANVAS		(gpaint_canvas_get_type ())
53 #define GPAINT_CANVAS(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GPAINT_TYPE_CANVAS, gpaint_canvas))
54 #define GPAINT_CANVAS_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GPAINT_TYPE_CANVAS, gpaint_canvas_class))
55 #define GPAINT_IS_CANVAS(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GPAINT_TYPE_CANVAS))
56 #define GPAINT_IS_CANVAS_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GPAINT_TYPE_CANVAS))
57 #define GPAINT_CANVAS_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GPAINT_TYPE_CANVAS, gpaint_canvas_class))
58 
59 GType gpaint_canvas_get_type (void);
60 
61 /* File to open when starting. */
62 static gchar** canvas_initial_filenames = 0;
63 
64 static gpaint_canvas* canvas_new(GtkDrawingArea *drawing_area);
65 static void canvas_copy_selection_to_clipboard(gpaint_canvas *canvas);
66 
67 static void canvas_clipboard_free (gpaint_clipboard *clipboard);
68 static gint canvas_clipboard_format_compare (GdkPixbufFormat *a, GdkPixbufFormat *b);
69 static void canvas_clipboard_send_buffer(GtkClipboard *gtk_clipboard, GtkSelectionData *selection_data, guint info, gpaint_canvas *canvas);
70 
71 static void
72 on_drawing_area_realize           (GtkWidget       *widget,
73                                   gpointer         user_data);
74 static gboolean
75 on_drawing_area_expose_event            (GtkWidget       *widget,
76                                         GdkEventExpose  *event,
77                                         gpointer         user_data);
78 static gboolean
79 on_drawing_area_motion_notify_event     (GtkWidget       *widget,
80                                         GdkEventMotion  *event,
81                                         gpointer         user_data);
82 static gboolean
83 on_drawing_area_button_press_event      (GtkWidget       *widget,
84                                         GdkEventButton  *event,
85                                         gpointer         user_data);
86 static gboolean
87 on_drawing_area_button_release_event    (GtkWidget       *widget,
88                                         GdkEventButton  *event,
89                                         gpointer         user_data);
90 static gboolean
91 on_drawing_area_focus_in_event          (GtkWidget       *widget,
92                                         GdkEventFocus   *event,
93                                         gpointer         user_data);
94 static gboolean
95 on_drawing_area_focus_out_event         (GtkWidget       *widget,
96                                         GdkEventFocus   *event,
97                                         gpointer         user_data);
98 static gboolean
99 on_drawing_area_key_release_event       (GtkWidget       *widget,
100                                         GdkEventKey     *event,
101                                         gpointer         user_data);
102 
103 /*
104  * Create the drawing area widget and place it in a scrolled view port. This
105  * function is called from ui.c when the main application window is created.
106  */
107 GtkWidget*
create_drawing_area_in_scroll_frame(gchar * widget_name,gchar * string1,gchar * string2,gint width,gint height)108 create_drawing_area_in_scroll_frame (
109         gchar *widget_name,
110         gchar *string1,
111         gchar *string2,
112         gint width,
113         gint height)
114 {
115     GtkWidget     *scrolledwindow;
116     GtkWidget     *viewport;
117     GtkWidget     *drawing_area;
118 
119     debug_fn();
120 
121     /* Create the scroll frame, view port, and drawing area widgets. */
122     scrolledwindow = gtk_scroll_frame_new (NULL, NULL);
123     gtk_scroll_frame_set_policy(GTK_SCROLL_FRAME (scrolledwindow),
124             GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
125 
126     viewport = gtk_viewport_new (NULL, NULL);
127     gtk_widget_set_name(viewport, "viewport");
128     gtk_widget_ref(viewport);
129     gtk_object_set_data_full(GTK_OBJECT (scrolledwindow), "viewport", viewport,
130                             (GtkDestroyNotify) gtk_widget_unref);
131 
132     gtk_widget_show(viewport);
133     gtk_container_add(GTK_CONTAINER (scrolledwindow), viewport);
134 
135     drawing_area = gtk_drawing_area_new();
136     gtk_widget_set_name(drawing_area, DRAWING_AREA);
137     gtk_widget_ref(drawing_area);
138     gtk_object_set_data_full(GTK_OBJECT(scrolledwindow), DRAWING_AREA, drawing_area,
139                             (GtkDestroyNotify) gtk_widget_unref);
140 
141     gtk_container_add(GTK_CONTAINER(viewport), drawing_area);
142 
143     gtk_widget_set_events(GTK_WIDGET(drawing_area),
144             GDK_EXPOSURE_MASK |
145             GDK_POINTER_MOTION_MASK |
146             GDK_POINTER_MOTION_HINT_MASK |
147             GDK_BUTTON_MOTION_MASK |
148             GDK_BUTTON1_MOTION_MASK |
149             GDK_BUTTON2_MOTION_MASK |
150             GDK_BUTTON3_MOTION_MASK |
151             GDK_BUTTON_PRESS_MASK |
152             GDK_BUTTON_RELEASE_MASK |
153             GDK_KEY_PRESS_MASK |
154             GDK_KEY_RELEASE_MASK |
155             GDK_PROPERTY_CHANGE_MASK |
156             GDK_VISIBILITY_NOTIFY_MASK |
157             GDK_FOCUS_CHANGE_MASK |
158             GDK_STRUCTURE_MASK |
159             GDK_ENTER_NOTIFY_MASK |
160             GDK_LEAVE_NOTIFY_MASK |
161             GDK_PROPERTY_CHANGE_MASK);
162     GTK_WIDGET_SET_FLAGS(drawing_area, GTK_CAN_FOCUS);
163     GTK_WIDGET_SET_FLAGS(drawing_area, GTK_CAN_DEFAULT);
164 
165     /* connect the realize event to the function that will initialize
166      * the canvas object. */
167     gtk_signal_connect(GTK_OBJECT(drawing_area), "realize",
168                        GTK_SIGNAL_FUNC(on_drawing_area_realize),
169                        NULL);
170     gtk_widget_show(drawing_area);
171     return scrolledwindow;
172 }
173 
174 /*
175  * Initialize the drawing area widget.
176  */
177 static void
on_drawing_area_realize(GtkWidget * drawing_area,gpointer user_data)178 on_drawing_area_realize           (GtkWidget       *drawing_area,
179                                   gpointer         user_data)
180 {
181     /* Create the canvas object and initialize the window objects. */
182     gpaint_canvas *canvas = canvas_new(GTK_DRAWING_AREA(drawing_area));
183     g_assert(canvas);
184     debug_fn();
185 
186     /* attach the application specific data object to the drawing area */
187     gtk_object_set_data_full(GTK_OBJECT(drawing_area),
188                              "user_data",
189                              canvas,
190                              (GtkDestroyNotify)canvas_destroy);
191 
192     gtk_drawing_area_size(GTK_DRAWING_AREA(drawing_area),
193                           canvas->drawing->width,
194                           canvas->drawing->height);
195 
196     /* save a reference to the drawing area in the top_level window */
197     gtk_widget_ref(drawing_area);
198     gtk_object_set_data_full(GTK_OBJECT(canvas->top_level),
199                              DRAWING_AREA,
200                              drawing_area,
201                              (GtkDestroyNotify)gtk_widget_unref);
202 
203     /* Connect the event handlers and pass the canvas object to the
204      * callback functions. */
205     gtk_signal_connect(GTK_OBJECT(drawing_area), "button_press_event",
206                        GTK_SIGNAL_FUNC(on_drawing_area_button_press_event),
207                        canvas);
208     gtk_signal_connect(GTK_OBJECT(drawing_area), "button_release_event",
209                        GTK_SIGNAL_FUNC(on_drawing_area_button_release_event),
210                        canvas);
211     gtk_signal_connect(GTK_OBJECT (drawing_area), "motion_notify_event",
212                        GTK_SIGNAL_FUNC(on_drawing_area_motion_notify_event),
213                        canvas);
214     gtk_signal_connect(GTK_OBJECT(drawing_area), "expose_event",
215                        GTK_SIGNAL_FUNC(on_drawing_area_expose_event),
216                        canvas);
217     gtk_signal_connect(GTK_OBJECT(drawing_area), "focus_in_event",
218                        GTK_SIGNAL_FUNC(on_drawing_area_focus_in_event),
219                        canvas);
220     gtk_signal_connect(GTK_OBJECT(drawing_area), "focus_out_event",
221                        GTK_SIGNAL_FUNC(on_drawing_area_focus_out_event),
222                        canvas);
223     gtk_signal_connect(GTK_OBJECT(drawing_area), "key_release_event",
224                        GTK_SIGNAL_FUNC(on_drawing_area_key_release_event),
225                        canvas);
226 }
227 
228 /*
229  * Copy the backing pixmap to the exposed area of the window.
230  */
231 static gboolean
on_drawing_area_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)232 on_drawing_area_expose_event            (GtkWidget       *widget,
233                                         GdkEventExpose  *event,
234                                         gpointer         user_data)
235 {
236     gpaint_canvas *canvas = (gpaint_canvas*)user_data;
237     gpaint_tool *tool = ACTIVE_TOOL(user_data);
238     debug_fn();
239     gdk_draw_pixmap(widget->window,
240                     widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
241                     canvas->drawing->backing_pixmap,
242                     event->area.x, event->area.y,
243                     event->area.x, event->area.y,
244                     event->area.width, event->area.height);
245     if (tool && tool->current_draw) tool->current_draw(tool);
246     return FALSE;
247 }
248 
249 /*
250  * Dispatch the motion event to the current tool object. The motion
251  * hint mask is used to collapse motion events. This prevents the
252  * the application from falling behind if events are dispatched by
253  * the X server faster than the application can process them.
254  */
255 static gboolean
on_drawing_area_motion_notify_event(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)256 on_drawing_area_motion_notify_event     (GtkWidget       *widget,
257                                         GdkEventMotion  *event,
258                                         gpointer         user_data)
259 {
260     gpaint_tool *tool = ACTIVE_TOOL(user_data);
261     int x, y;
262     GdkModifierType state;
263 
264     if (tool && tool->motion)
265     {
266         if (event->is_hint)
267         {
268             gdk_window_get_pointer (event->window, &x, &y, &state);
269         }
270         else
271         {
272             x = event->x;
273             y = event->y;
274             state = event->state;
275         }
276 
277         if (state & GDK_BUTTON1_MASK)
278         {
279             (*tool->motion)(tool, x, y);
280         }
281     }
282     return TRUE;
283 }
284 
285 /*
286  * Dispatch the mouse button press to the active tool.
287  */
288 static gboolean
on_drawing_area_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)289 on_drawing_area_button_press_event      (GtkWidget       *widget,
290                                         GdkEventButton  *event,
291                                         gpointer         user_data)
292 {
293     gpaint_tool *tool = ACTIVE_TOOL(user_data);
294     if (event->button==1 && tool && tool->button_press)
295     {
296         (*tool->button_press)(tool, event->x, event->y);
297     }
298     return FALSE;
299 }
300 
301 /*
302  * Dispatch the mouse button release to the active tool.
303  */
304 static gboolean
on_drawing_area_button_release_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)305 on_drawing_area_button_release_event    (GtkWidget       *widget,
306                                         GdkEventButton  *event,
307                                         gpointer         user_data)
308 {
309     gpaint_tool *tool = ACTIVE_TOOL(user_data);
310     if (event->button==1 && tool && tool->button_release)
311     {
312         (*tool->button_release)(tool, event->x, event->y);
313     }
314     return FALSE;
315 }
316 
317 /*
318  * Dispatch the focus in event to the active tool.
319  */
320 static gboolean
on_drawing_area_focus_in_event(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)321 on_drawing_area_focus_in_event          (GtkWidget       *widget,
322                                         GdkEventFocus   *event,
323                                         gpointer         user_data)
324 {
325     gpaint_canvas *canvas = CANVAS(user_data);
326     debug_fn1("canvas=%p", canvas);
327     canvas_focus_gained(canvas);
328     return FALSE;
329 }
330 
331 /*
332  * Dispatch the focus out event to the active tool.
333  */
334 static gboolean
on_drawing_area_focus_out_event(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)335 on_drawing_area_focus_out_event         (GtkWidget       *widget,
336                                         GdkEventFocus   *event,
337                                         gpointer         user_data)
338 {
339     gpaint_canvas *canvas = CANVAS(user_data);
340     debug_fn1("canvas=%p", canvas);
341     canvas_focus_lost(canvas);
342     return FALSE;
343 }
344 
345 /*
346  * Dispatch the key release to the active tool.
347  */
348 static gboolean
on_drawing_area_key_release_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)349 on_drawing_area_key_release_event       (GtkWidget       *widget,
350                                         GdkEventKey     *event,
351                                         gpointer         user_data)
352 {
353     gpaint_tool *tool = ACTIVE_TOOL(user_data);
354     if (tool && tool->key_release)
355     {
356         (*tool->key_release)(tool, event);
357     }
358     return FALSE;
359 }
360 
361 /*
362  * Save the application command line arguments. The first
363  * argument is the filename to be initially opened. A
364  * blank drawing is created if no file name is given.
365  */
366 void
canvas_init_arg(int argc,char * argv[])367 canvas_init_arg(int argc, char* argv[])
368 {
369     int i;
370     if (argc > 1)
371     {
372         canvas_initial_filenames = calloc(sizeof(char*), argc - 1);
373         for (i = 1; i < argc; i++)
374             canvas_initial_filenames[i - 1] = argv[i];
375     }
376     return;
377 }
378 
379 
380 /*
381  * Lookup the canvas object from a widget.
382  */
383 gpaint_canvas*
canvas_lookup(GtkWidget * widget)384 canvas_lookup(GtkWidget *widget)
385 {
386     GtkWidget *cw;
387     gpaint_canvas *canvas;
388     cw = lookup_widget(widget, DRAWING_AREA);
389     g_assert(cw) ;
390     canvas = (gpaint_canvas*)gtk_object_get_data(GTK_OBJECT(cw), "user_data");
391     g_assert(canvas);
392     return canvas;
393 }
394 
395 /*
396  * Create a new canvas object. The canvas object is created when the drawing
397  * area window is realized.
398  */
399 gpaint_canvas *
canvas_new(GtkDrawingArea * drawing_area)400 canvas_new(GtkDrawingArea *drawing_area)
401 {
402     gpaint_canvas *canvas = 0;
403     gpaint_drawing *drawing = 0;
404     GdkDrawable *d = GTK_WIDGET(drawing_area)->window;
405     GdkGC *gc;
406     GdkColor black;
407     GdkColor white;
408 
409     /* Create the gc from the drawing area window. */
410     gc = gdk_gc_new(d);
411     g_assert(gc);
412     gdk_gc_ref(gc);
413 
414     gdk_color_black(gdk_colormap_get_system(), &black);
415     gdk_color_white(gdk_colormap_get_system(), &white);
416     gdk_gc_set_foreground(gc, &black);
417     gdk_gc_set_background(gc, &white);
418     gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
419 
420     /* Create the canvas object */
421 //    canvas = (gpaint_canvas*)g_new0(gpaint_canvas, 1);
422     canvas = g_object_new (GPAINT_TYPE_CANVAS, NULL);
423     g_assert(canvas);
424     canvas->top_level = gtk_widget_get_toplevel(GTK_WIDGET(drawing_area));
425     canvas->drawing_area = drawing_area;
426     canvas->gc = gc;
427     canvas->busy_cursor = gdk_cursor_new(GDK_WATCH);
428     canvas->arrow_cursor = gdk_cursor_new(GDK_LEFT_PTR);
429     canvas->cursor = canvas->arrow_cursor;
430     canvas->active_tool = 0;
431     canvas->saved_tool = 0;
432     canvas->paste_tool = paste_create("paste");
433     canvas->selection = selection_new(drawing_area);
434 
435     /* Create the drawing object */
436     if (canvas_initial_filenames)
437     { /* only open the first one for now; open additonal ones TO DO */
438 
439         drawing = drawing_new_from_file(canvas->drawing_area, canvas->gc, canvas_initial_filenames[0]);
440         if (!drawing)
441         {
442             g_message("Failed to open drawing file %s", canvas_initial_filenames[0]);
443         }
444         free(canvas_initial_filenames);
445         canvas_initial_filenames = 0;  /* use only in the first window */
446     }
447     if (!drawing)
448     {
449         drawing = drawing_new_blank(canvas->drawing_area, canvas->gc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
450     }
451     g_assert(drawing);
452     canvas->drawing = drawing;
453     selection_size(canvas->selection, drawing->width, drawing->height);
454 
455     return canvas;
456 }
457 
458 GType
gpaint_canvas_get_type(void)459 gpaint_canvas_get_type (void)
460 {
461     static GType object_type = 0;
462 
463     if (!object_type)
464     {
465 	static const GTypeInfo object_info =
466 	{
467 	    sizeof (gpaint_canvas_class),
468 	    (GBaseInitFunc) NULL,
469 	    (GBaseFinalizeFunc) NULL,
470 	    (GClassInitFunc) NULL,
471 	    NULL,	/* class_finalize */
472 	    NULL,	/* class_data */
473 	    sizeof (gpaint_canvas),
474 	    0,
475 	    (GInstanceInitFunc) NULL,
476 	};
477 
478 	object_type = g_type_register_static (G_TYPE_OBJECT,
479 						"GpaintCanvas",
480 						&object_info, 0);
481     }
482 
483     return object_type;
484 }
485 
486 void
canvas_destroy(gpaint_canvas * canvas)487 canvas_destroy(gpaint_canvas *canvas)
488 {
489     debug_fn();
490     g_assert(canvas);
491 
492     if (canvas->paste_tool)
493     {
494         gpaint_tool *tool = canvas->paste_tool;
495         g_assert(tool->destroy);
496         (*tool->destroy)(tool);
497     }
498 
499     drawing_destroy(canvas->drawing);
500     selection_delete(canvas->selection);
501     gdk_gc_unref(canvas->gc);
502     gdk_cursor_destroy(canvas->arrow_cursor);
503     gdk_cursor_destroy(canvas->busy_cursor);
504 //    memset(canvas, 0xBEBE, sizeof(canvas)); /* debugging aid */
505 //    g_free(canvas);
506     g_object_unref(canvas);
507     debug("canvas_destroy() returning");
508 }
509 
510 /*
511  * Display the new drawing and destroy the current drawing.
512  */
513 void
canvas_set_drawing(gpaint_canvas * canvas,gpaint_drawing * new_drawing)514 canvas_set_drawing(gpaint_canvas *canvas, gpaint_drawing *new_drawing)
515 {
516     gpaint_drawing *old_drawing;
517     g_assert(canvas);
518     g_assert(new_drawing);
519 
520     old_drawing = canvas->drawing;
521 
522     canvas->drawing = new_drawing;
523     selection_remove_points(canvas->selection);
524     if (canvas->active_tool)
525     {
526         canvas->active_tool->drawing = canvas->drawing;
527     }
528     gtk_drawing_area_size(
529                 GTK_DRAWING_AREA(canvas->drawing_area),
530                 canvas->drawing->width,
531                 canvas->drawing->height);
532     selection_size(canvas->selection, canvas->drawing->width, canvas->drawing->height);
533     drawing_destroy(old_drawing);
534     canvas_redraw(canvas);
535 }
536 
537 /*
538  * Resize the canvas to the current drawing size. Should be called
539  * when the drawing size has been changed.
540  */
541 void
canvas_resize(gpaint_canvas * canvas)542 canvas_resize(gpaint_canvas *canvas)
543 {
544     selection_remove_points(canvas->selection);
545     selection_size(canvas->selection, canvas->drawing->width, canvas->drawing->height);
546     gtk_drawing_area_size(
547                 GTK_DRAWING_AREA(canvas->drawing_area),
548                 canvas->drawing->width,
549                 canvas->drawing->height);
550     canvas_redraw(canvas);
551 }
552 
553 
554 /*
555  * Set the active drawing tool object.
556  */
557 void
canvas_set_tool(gpaint_canvas * canvas,gpaint_tool * new_tool)558 canvas_set_tool(gpaint_canvas* canvas, gpaint_tool *new_tool)
559 {
560     gpaint_tool *old_tool = canvas->active_tool;
561 
562     if (old_tool && old_tool->deselect)
563     {
564         (*old_tool->deselect)(old_tool);
565     }
566 
567     canvas->active_tool = new_tool;
568     if (!canvas->active_tool)      /* null means remove active tool */
569     {
570         canvas->cursor = canvas->arrow_cursor;
571     }
572     else
573     {
574         new_tool->drawing = canvas->drawing;
575         new_tool->canvas = canvas;
576         if (new_tool->select)
577         {
578             (*new_tool->select)(new_tool);
579         }
580         canvas->cursor = new_tool->cursor;
581     }
582     gdk_window_set_cursor(canvas->drawing->window, canvas->cursor);
583 }
584 
585 void
canvas_begin_busy_cursor(gpaint_canvas * canvas)586 canvas_begin_busy_cursor(gpaint_canvas *canvas)
587 {
588     canvas_commit_change(canvas);
589     gdk_window_set_cursor(canvas->top_level->window, canvas->busy_cursor);
590     gdk_window_set_cursor(canvas->drawing->window, canvas->busy_cursor);
591     gdk_flush();
592 }
593 
594 void
canvas_end_busy_cursor(gpaint_canvas * canvas)595 canvas_end_busy_cursor(gpaint_canvas *canvas)
596 {
597     gdk_window_set_cursor(canvas->top_level->window, canvas->arrow_cursor);
598     if (canvas->cursor)
599     {
600         gdk_window_set_cursor(canvas->drawing->window, canvas->cursor);
601     }
602     else
603     {
604         gdk_window_set_cursor(canvas->drawing->window, canvas->arrow_cursor);
605     }
606     gdk_flush();
607 }
608 
609 void
canvas_focus_gained(gpaint_canvas * canvas)610 canvas_focus_gained(gpaint_canvas *canvas)
611 {
612     gpaint_tool *tool = canvas->active_tool;
613     debug_fn1("canvas=%p", canvas);
614 
615     selection_enable_flash(canvas->selection);
616     canvas->has_focus = TRUE;
617     if (tool && tool->change)
618     {
619         (*tool->change)(tool, GpaintFocusIn, NULL);
620     }
621 }
622 
623 void
canvas_focus_lost(gpaint_canvas * canvas)624 canvas_focus_lost(gpaint_canvas *canvas)
625 {
626     gpaint_tool *tool = canvas->active_tool;
627     debug_fn1("canvas=%p", canvas);
628 
629     selection_disable_flash(canvas->selection);
630     canvas->has_focus = FALSE;
631     if (tool && tool->change)
632     {
633         (*tool->change)(tool, GpaintFocusOut, NULL);
634     }
635 }
636 
637 void
canvas_redraw(gpaint_canvas * canvas)638 canvas_redraw(gpaint_canvas *canvas)
639 {
640     GtkWidget *widget = GTK_WIDGET(canvas->drawing_area);
641     int width;
642     int height;
643 
644     gdk_window_get_size(widget->window, &width, &height);
645     gtk_widget_queue_draw_area(widget, 0, 0, width, height);
646     gtk_widget_queue_draw(widget);
647 }
648 
649 void
canvas_begin_paste_mode(gpaint_canvas * canvas)650 canvas_begin_paste_mode(gpaint_canvas *canvas)
651 {
652     gpaint_clipboard *clipboard = canvas_clipboard(canvas);
653     canvas_commit_change(canvas);
654 //    if (clipboard && point_array_size(clipboard->points))
655     {
656         if (canvas->active_tool != canvas->paste_tool)
657         {
658             canvas->saved_tool = canvas->active_tool;
659             canvas_set_tool(canvas, canvas->paste_tool);
660         }
661     }
662 }
663 
664 void
canvas_end_paste_mode(gpaint_canvas * canvas)665 canvas_end_paste_mode(gpaint_canvas *canvas)
666 {
667     if (canvas->active_tool == canvas->paste_tool)
668     {
669         canvas_set_tool(canvas, canvas->saved_tool);
670     }
671 }
672 
673 void
canvas_cut(gpaint_canvas * canvas)674 canvas_cut(gpaint_canvas *canvas)
675 {
676     canvas_commit_change(canvas);
677     if (canvas_has_selection(canvas))
678     {
679         selection_disable_flash(canvas->selection);
680         canvas_copy_selection_to_clipboard(canvas);
681         drawing_clear_selection(canvas->drawing, selection_points(canvas->selection));
682         selection_enable_flash(canvas->selection);
683     }
684 }
685 
686 void
canvas_copy(gpaint_canvas * canvas)687 canvas_copy(gpaint_canvas *canvas)
688 {
689     canvas_commit_change(canvas);
690     if (canvas_has_selection(canvas))
691     {
692         selection_disable_flash(canvas->selection);
693         canvas_copy_selection_to_clipboard(canvas);
694         selection_enable_flash(canvas->selection);
695     }
696 }
697 
698 void
canvas_clear(gpaint_canvas * canvas)699 canvas_clear(gpaint_canvas *canvas)
700 {
701 
702     if (canvas_has_selection(canvas))
703     {
704         selection_disable_flash(canvas->selection);
705         drawing_clear_selection(canvas->drawing, selection_points(canvas->selection));
706         selection_enable_flash(canvas->selection);
707     }
708     else
709     {
710         drawing_clear(canvas->drawing);
711         canvas_redraw(canvas);
712     }
713 }
714 
715 void
canvas_select_all(gpaint_canvas * canvas)716 canvas_select_all(gpaint_canvas *canvas)
717 {
718     GdkRectangle rect;
719     canvas_commit_change(canvas);
720     rect.x = 0;
721     rect.y = 0;
722     rect.width = canvas->drawing->width;
723     rect.height = canvas->drawing->height;
724     selection_set_rectangle(canvas->selection, rect);
725 }
726 
727 gboolean
canvas_has_selection(gpaint_canvas * canvas)728 canvas_has_selection(gpaint_canvas *canvas)
729 {
730     return (selection_num_points(canvas->selection) > 2);
731 }
732 
733 gpaint_clipboard *
canvas_clipboard(gpaint_canvas * canvas)734 canvas_clipboard(gpaint_canvas *canvas)
735 {
736     /* create the single clipboard */
737     if (!clipboard)
738     {
739 	GSList *list;
740 
741         clipboard = g_new0(gpaint_clipboard, 1);
742         clipboard->image = 0;
743         clipboard->points = point_array_new();
744 
745 /* create gobject for clipboard notifications */
746 	g_object_set_data_full (G_OBJECT (canvas), GPAINT_CLIPBOARD_KEY,
747 				clipboard, (GDestroyNotify) canvas_clipboard_free);
748 
749 /* create list of pixbuf formats for clipboard format negotiation */
750 
751         clipboard->pixbuf_formats =
752 		g_slist_sort (gdk_pixbuf_get_formats(),
753 				(GCompareFunc) canvas_clipboard_format_compare);
754 	for (list = clipboard->pixbuf_formats; list; list = g_slist_next (list))
755 	{
756 	    GdkPixbufFormat *format = list->data;
757 
758 	    if (gdk_pixbuf_format_is_writable (format))
759 	    {
760 		gchar **mime_types;
761 		gchar **type;
762 
763 		mime_types = gdk_pixbuf_format_get_mime_types (format);
764 
765 		for (type = mime_types; *type; type++)
766 		    clipboard->n_target_entries++;
767 
768 		g_strfreev (mime_types);
769 	    }
770 	}
771 
772 	if (clipboard->n_target_entries > 0)
773 	{
774 	    gint i = 0;
775 
776 	    clipboard->target_entries = g_new0(GtkTargetEntry,
777 						clipboard->n_target_entries);
778 	    clipboard->savers 	      = g_new0(gchar*,
779 						clipboard->n_target_entries + 1);
780 
781 	    for (list = clipboard->pixbuf_formats; list; list = g_slist_next (list))
782 	    {
783 	        GdkPixbufFormat *format = list->data;
784 
785 	        if (gdk_pixbuf_format_is_writable (format))
786 	        {
787 		    gchar *format_name;
788 		    gchar **mime_types;
789 		    gchar **type;
790 
791 		    format_name = gdk_pixbuf_format_get_name (format);
792 		    mime_types = gdk_pixbuf_format_get_mime_types (format);
793 
794 		    for (type = mime_types; *type; type++)
795 		    {
796 			gchar *mime_type = *type;
797 
798 			clipboard->target_entries[i].target = g_strdup (mime_type);
799 			clipboard->target_entries[i].flags  = 0;
800 			clipboard->target_entries[i].info   = i;
801 
802 			clipboard->savers[i]                = g_strdup (format_name);
803 
804 			i++;
805 		    }
806 
807 		    g_strfreev (mime_types);
808 		    g_free (format_name);
809 		}
810 	    }
811 	}
812     }
813     return clipboard;
814 }
815 
816 static void
canvas_clipboard_free(gpaint_clipboard * clipboard)817 canvas_clipboard_free (gpaint_clipboard *clipboard)
818 {
819     g_slist_free (clipboard->pixbuf_formats);
820     g_free (clipboard->target_entries);
821     g_strfreev (clipboard->savers);
822     g_free (clipboard);
823 }
824 
825 static void
canvas_copy_selection_to_clipboard(gpaint_canvas * canvas)826 canvas_copy_selection_to_clipboard(gpaint_canvas *canvas)
827 {
828     gpaint_clipboard *clipboard = canvas_clipboard(canvas);
829     GtkClipboard *gtk_clipboard;
830 
831     if (clipboard->image)
832     {
833         image_free(clipboard->image);
834     }
835     clipboard->image = image_from_selection(
836                             canvas->drawing->backing_pixmap,
837                             selection_points(canvas->selection));
838     point_array_copy(clipboard->points, selection_points(canvas->selection));
839 
840     gtk_clipboard = gtk_clipboard_get_for_display (gdk_display_get_default(),
841 						   GDK_SELECTION_CLIPBOARD);
842     if (!gtk_clipboard)
843         return;
844 
845     if (clipboard->image)
846     {
847         gtk_clipboard_set_with_owner (gtk_clipboard,
848     					clipboard->target_entries,
849 					clipboard->n_target_entries,
850 					(GtkClipboardGetFunc) canvas_clipboard_send_buffer,
851 					(GtkClipboardClearFunc) NULL,
852 					G_OBJECT (canvas));
853     }
854     else if (gtk_clipboard_get_owner (gtk_clipboard) == G_OBJECT(canvas))
855     {
856         gtk_clipboard_clear (gtk_clipboard);
857     }
858 }
859 
860 static GdkPixbuf*
clipboard_pixbuf(gpaint_clipboard * clipboard)861 clipboard_pixbuf(gpaint_clipboard *clipboard) {
862     return image_pixbuf(clipboard->image);
863 }
864 
865 
866 static void
canvas_clipboard_send_buffer(GtkClipboard * gtk_clipboard,GtkSelectionData * selection_data,guint info,gpaint_canvas * canvas)867 canvas_clipboard_send_buffer(GtkClipboard	*gtk_clipboard,
868 			     GtkSelectionData	*selection_data,
869 			     guint		 info,
870 			     gpaint_canvas	*canvas)
871 {
872     gpaint_clipboard *clipboard = canvas_clipboard(canvas);
873     GdkPixbuf *pixbuf = clipboard_pixbuf(clipboard);
874 
875     if (pixbuf)
876     {
877         GdkAtom atom = gdk_atom_intern (clipboard->target_entries[info].target,
878 					FALSE);
879 
880 	g_print ("sending pixbuf data as '%s' (%s)\n",
881 			clipboard->target_entries[info].target,
882 			clipboard->savers[info]);
883 	gchar *buffer;
884 	gsize buffer_size;
885 	GError *error = NULL;
886 
887 	g_return_if_fail (selection_data != NULL);
888 	g_return_if_fail (atom != GDK_NONE);
889 	g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
890 	g_return_if_fail (clipboard->savers[info] != NULL);
891 
892 	if (gdk_pixbuf_save_to_buffer (pixbuf,
893 					&buffer, &buffer_size, clipboard->savers[info],
894 					&error, NULL))
895 	{
896 	    gtk_selection_data_set (selection_data, atom,
897 					8, (guchar*) buffer, buffer_size);
898         }
899     }
900 }
901 
902 static gint
canvas_clipboard_format_compare(GdkPixbufFormat * a,GdkPixbufFormat * b)903 canvas_clipboard_format_compare (GdkPixbufFormat *a,
904 				 GdkPixbufFormat *b)
905 {
906     gchar *a_name = gdk_pixbuf_format_get_name (a);
907     gchar *b_name = gdk_pixbuf_format_get_name (b);
908     gint retval = 0;
909 
910 #ifdef GDK_WINDOWING_WIN32
911     /*  move BMP to the front of the list  */
912     if (g_ascii_strncasecmp (a_name, "bmp", strlen("bmp")) == 0)
913         retval = -1;
914     else if (g_ascii_strncasecmp (b_name, "bmp", strlen("bmp")) == 0)
915         retval = 1;
916     else
917 #endif
918 
919     /*  move PNG to the front of the list  */
920     if (g_ascii_strncasecmp (a_name, "png", strlen("png")) == 0)
921         retval = -1;
922     else if (g_ascii_strncasecmp (b_name, "png", strlen("png")) == 0)
923         retval = 1;
924 
925     /*  move JPEG to the end of the list  */
926     else if (g_ascii_strncasecmp (a_name, "jpeg", strlen("jpeg")) == 0)
927         retval = 1;
928     else if (g_ascii_strncasecmp (b_name, "jpeg", strlen("jpeg")) == 0)
929         retval = -1;
930 
931     /*  move GIF to the end of the list  */
932     else if (g_ascii_strncasecmp (a_name, "gif", strlen("gif")) == 0)
933         retval = 1;
934     else if (g_ascii_strncasecmp (b_name, "gif", strlen("gif")) == 0)
935         retval = -1;
936 
937     g_free (a_name);
938     g_free (b_name);
939 
940     return retval;
941 }
942 
canvas_commit_change(gpaint_canvas * canvas)943 void canvas_commit_change(gpaint_canvas *canvas)
944 {
945     gpaint_tool * tool = canvas->active_tool;
946     if (tool && tool->commit_change)
947         tool->commit_change(tool);
948 }
949