]> git.donarmstrong.com Git - xournal.git/blob - src/xo-clipboard.c
Image patch
[xournal.git] / src / xo-clipboard.c
1 /*
2  *  This program is free software; you can redistribute it and/or
3  *  modify it under the terms of the GNU General Public
4  *  License as published by the Free Software Foundation; either
5  *  version 2 of the License, or (at your option) any later version.
6  *
7  *  This software is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
14  */
15
16 #ifdef HAVE_CONFIG_H
17 #  include <config.h>
18 #endif
19
20 #include <string.h>
21 #include <gtk/gtk.h>
22
23 #include "xournal.h"
24 #include "xo-callbacks.h"
25 #include "xo-interface.h"
26 #include "xo-support.h"
27 #include "xo-misc.h"
28 #include "xo-paint.h"
29 #include "xo-image.h"
30
31
32 void callback_clipboard_get(GtkClipboard *clipboard,
33                             GtkSelectionData *selection_data,
34                             guint info, gpointer user_data)
35 {
36   int length;
37   
38   g_memmove(&length, user_data, sizeof(int));
39   gtk_selection_data_set(selection_data,
40      gdk_atom_intern("_XOURNAL", FALSE), 8, user_data, length);
41 }
42
43 void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
44 {
45   g_free(user_data);
46 }
47
48 void selection_to_clip(void)
49 {
50   int bufsz, nitems, val;
51   char *buf, *p;
52   GList *list;
53   struct Item *item;
54   GtkTargetEntry target;
55   
56   if (ui.selection == NULL) return;
57   bufsz = 2*sizeof(int) // bufsz, nitems
58         + sizeof(struct BBox); // bbox
59   nitems = 0;
60   for (list = ui.selection->items; list != NULL; list = list->next) {
61     item = (struct Item *)list->data;
62     nitems++;
63     if (item->type == ITEM_STROKE) {
64       bufsz+= sizeof(int) // type
65             + sizeof(struct Brush) // brush
66             + sizeof(int) // num_points
67             + 2*item->path->num_points*sizeof(double); // the points
68       if (item->brush.variable_width)
69         bufsz += (item->path->num_points-1)*sizeof(double); // the widths
70     }
71     else if (item->type == ITEM_TEXT) {
72       bufsz+= sizeof(int) // type
73             + sizeof(struct Brush) // brush
74             + 2*sizeof(double) // bbox upper-left
75             + sizeof(int) // text len
76             + strlen(item->text)+1 // text
77             + sizeof(int) // font_name len
78             + strlen(item->font_name)+1 // font_name
79             + sizeof(double); // font_size
80     }
81     else if (item->type == ITEM_IMAGE) {
82       if (item->image_png == NULL) {
83         set_cursor_busy(TRUE);
84         if (!gdk_pixbuf_save_to_buffer(item->image, &item->image_png, &item->image_png_len, "png", NULL, NULL))
85           item->image_png_len = 0;       // failed for some reason, so forget it
86         set_cursor_busy(FALSE);
87       }
88       bufsz+= sizeof(int) // type
89         + sizeof(struct BBox)
90         + sizeof(gsize) // png_buflen
91         + item->image_png_len;
92     }
93     else bufsz+= sizeof(int); // type
94   }
95   p = buf = g_malloc(bufsz);
96   g_memmove(p, &bufsz, sizeof(int)); p+= sizeof(int);
97   g_memmove(p, &nitems, sizeof(int)); p+= sizeof(int);
98   g_memmove(p, &ui.selection->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
99   for (list = ui.selection->items; list != NULL; list = list->next) {
100     item = (struct Item *)list->data;
101     g_memmove(p, &item->type, sizeof(int)); p+= sizeof(int);
102     if (item->type == ITEM_STROKE) {
103       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
104       g_memmove(p, &item->path->num_points, sizeof(int)); p+= sizeof(int);
105       g_memmove(p, item->path->coords, 2*item->path->num_points*sizeof(double));
106       p+= 2*item->path->num_points*sizeof(double);
107       if (item->brush.variable_width) {
108         g_memmove(p, item->widths, (item->path->num_points-1)*sizeof(double));
109         p+= (item->path->num_points-1)*sizeof(double);
110       }
111     }
112     if (item->type == ITEM_TEXT) {
113       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
114       g_memmove(p, &item->bbox.left, sizeof(double)); p+= sizeof(double);
115       g_memmove(p, &item->bbox.top, sizeof(double)); p+= sizeof(double);
116       val = strlen(item->text);
117       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
118       g_memmove(p, item->text, val+1); p+= val+1;
119       val = strlen(item->font_name);
120       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
121       g_memmove(p, item->font_name, val+1); p+= val+1;
122       g_memmove(p, &item->font_size, sizeof(double)); p+= sizeof(double);
123     }
124     if (item->type == ITEM_IMAGE) {
125       g_memmove(p, &item->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
126       g_memmove(p, &item->image_png_len, sizeof(gsize)); p+= sizeof(gsize);
127       if (item->image_png_len > 0) {
128         g_memmove(p, item->image_png, item->image_png_len); p+= item->image_png_len;
129       }
130     }
131   }
132   
133   target.target = "_XOURNAL";
134   target.flags = 0;
135   target.info = 0;
136   
137   gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), 
138        &target, 1,
139        callback_clipboard_get, callback_clipboard_clear, buf);
140 }
141
142 // local paste within xournal
143 void clipboard_paste_from_xournal(GtkSelectionData *sel_data)
144 {
145   unsigned char *p;
146   int nitems, npts, i, len;
147   struct Item *item;
148   double hoffset, voffset, cx, cy;
149   double *pf;
150   int sx, sy, wx, wy;
151   
152   reset_selection();
153   
154   ui.selection = g_new(struct Selection, 1);
155   p = sel_data->data + sizeof(int);
156   g_memmove(&nitems, p, sizeof(int)); p+= sizeof(int);
157   ui.selection->type = ITEM_SELECTRECT;
158   ui.selection->layer = ui.cur_layer;
159   g_memmove(&ui.selection->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
160   ui.selection->items = NULL;
161   
162   // find by how much we translate the pasted selection
163   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
164   gdk_window_get_geometry(GTK_WIDGET(canvas)->window, NULL, NULL, &wx, &wy, NULL);
165   gnome_canvas_window_to_world(canvas, sx + wx/2, sy + wy/2, &cx, &cy);
166   cx -= ui.cur_page->hoffset;
167   cy -= ui.cur_page->voffset;
168   if (cx + (ui.selection->bbox.right-ui.selection->bbox.left)/2 > ui.cur_page->width)
169     cx = ui.cur_page->width - (ui.selection->bbox.right-ui.selection->bbox.left)/2;
170   if (cx - (ui.selection->bbox.right-ui.selection->bbox.left)/2 < 0)
171     cx = (ui.selection->bbox.right-ui.selection->bbox.left)/2;
172   if (cy + (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 > ui.cur_page->height)
173     cy = ui.cur_page->height - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
174   if (cy - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 < 0)
175     cy = (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
176   hoffset = cx - (ui.selection->bbox.right+ui.selection->bbox.left)/2;
177   voffset = cy - (ui.selection->bbox.top+ui.selection->bbox.bottom)/2;
178   ui.selection->bbox.left += hoffset;
179   ui.selection->bbox.right += hoffset;
180   ui.selection->bbox.top += voffset;
181   ui.selection->bbox.bottom += voffset;
182
183   ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
184       gnome_canvas_rect_get_type(), "width-pixels", 1,
185       "outline-color-rgba", 0x000000ff,
186       "fill-color-rgba", 0x80808040,
187       "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, 
188       "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
189   make_dashed(ui.selection->canvas_item);
190
191   while (nitems-- > 0) {
192     item = g_new(struct Item, 1);
193     ui.selection->items = g_list_append(ui.selection->items, item);
194     ui.cur_layer->items = g_list_append(ui.cur_layer->items, item);
195     ui.cur_layer->nitems++;
196     g_memmove(&item->type, p, sizeof(int)); p+= sizeof(int);
197     if (item->type == ITEM_STROKE) {
198       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
199       g_memmove(&npts, p, sizeof(int)); p+= sizeof(int);
200       item->path = gnome_canvas_points_new(npts);
201       pf = (double *)p;
202       for (i=0; i<npts; i++) {
203         item->path->coords[2*i] = pf[2*i] + hoffset;
204         item->path->coords[2*i+1] = pf[2*i+1] + voffset;
205       }
206       p+= 2*item->path->num_points*sizeof(double);
207       if (item->brush.variable_width) {
208         item->widths = g_memdup(p, (item->path->num_points-1)*sizeof(double));
209         p+= (item->path->num_points-1)*sizeof(double);
210       }
211       else item->widths = NULL;
212       update_item_bbox(item);
213       make_canvas_item_one(ui.cur_layer->group, item);
214     }
215     if (item->type == ITEM_TEXT) {
216       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
217       g_memmove(&item->bbox.left, p, sizeof(double)); p+= sizeof(double);
218       g_memmove(&item->bbox.top, p, sizeof(double)); p+= sizeof(double);
219       item->bbox.left += hoffset;
220       item->bbox.top += voffset;
221       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
222       item->text = g_malloc(len+1);
223       g_memmove(item->text, p, len+1); p+= len+1;
224       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
225       item->font_name = g_malloc(len+1);
226       g_memmove(item->font_name, p, len+1); p+= len+1;
227       g_memmove(&item->font_size, p, sizeof(double)); p+= sizeof(double);
228       make_canvas_item_one(ui.cur_layer->group, item);
229     }
230     if (item->type == ITEM_IMAGE) {
231       item->canvas_item = NULL;
232       item->image_png = NULL;
233       item->image_png_len = 0;
234       g_memmove(&item->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
235       item->bbox.left += hoffset;
236       item->bbox.right += hoffset;
237       item->bbox.top += voffset;
238       item->bbox.bottom += voffset;
239       g_memmove(&item->image_png_len, p, sizeof(gsize)); p+= sizeof(gsize);
240       if (item->image_png_len > 0) {
241         item->image_png = g_memdup(p, item->image_png_len);
242         item->image = pixbuf_from_buffer(item->image_png, item->image_png_len);
243         p+= item->image_png_len;
244       } else {
245         item->image = NULL;
246       }
247       make_canvas_item_one(ui.cur_layer->group, item);
248     }
249   }
250
251   prepare_new_undo();
252   undo->type = ITEM_PASTE;
253   undo->layer = ui.cur_layer;
254   undo->itemlist = g_list_copy(ui.selection->items);  
255   
256   gtk_selection_data_free(sel_data);
257   update_copy_paste_enabled();
258   update_color_menu();
259   update_thickness_buttons();
260   update_color_buttons();
261   update_font_button();  
262   update_cursor(); // FIXME: can't know if pointer is within selection!
263 }
264
265 // paste an external image
266 void clipboard_paste_image(GdkPixbuf *pixbuf)
267 {
268   double pt[2];
269
270   reset_selection();
271
272   get_current_pointer_coords(pt);
273   set_current_page(pt);  
274
275   create_image_from_pixbuf(pixbuf, pt);
276 }
277
278 // work out what format the clipboard data is in, and paste accordingly
279 void clipboard_paste(void)
280 {
281   GtkSelectionData *sel_data;
282   GtkClipboard *clipboard;
283   GdkPixbuf *pixbuf;
284
285   if (ui.cur_layer == NULL) return;
286   
287   ui.cur_item_type = ITEM_PASTE;
288   clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
289   // try xournal data
290   sel_data = gtk_clipboard_wait_for_contents(
291       clipboard,
292       gdk_atom_intern("_XOURNAL", FALSE));
293   ui.cur_item_type = ITEM_NONE;
294   if (sel_data != NULL) { 
295     clipboard_paste_from_xournal(sel_data);
296     return;
297   } 
298   // try image data
299   pixbuf = gtk_clipboard_wait_for_image(clipboard);
300   if (pixbuf != NULL) {
301     clipboard_paste_image(pixbuf);
302     return;
303   }
304 }