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.
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.
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/>.
24 #include "xo-callbacks.h"
25 #include "xo-interface.h"
26 #include "xo-support.h"
32 void callback_clipboard_get(GtkClipboard *clipboard,
33 GtkSelectionData *selection_data,
34 guint info, gpointer user_data)
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);
43 void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
48 void selection_to_clip(void)
50 int bufsz, nitems, val;
54 GtkTargetEntry target;
56 if (ui.selection == NULL) return;
57 bufsz = 2*sizeof(int) // bufsz, nitems
58 + sizeof(struct BBox); // bbox
60 for (list = ui.selection->items; list != NULL; list = list->next) {
61 item = (struct Item *)list->data;
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
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
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);
88 bufsz+= sizeof(int) // type
90 + sizeof(gsize) // png_buflen
91 + item->image_png_len;
93 else bufsz+= sizeof(int); // type
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);
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);
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;
133 target.target = "_XOURNAL";
137 gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
139 callback_clipboard_get, callback_clipboard_clear, buf);
142 // local paste within xournal
143 void clipboard_paste_from_xournal(GtkSelectionData *sel_data)
146 int nitems, npts, i, len;
148 double hoffset, voffset, cx, cy;
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;
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;
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);
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);
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;
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);
211 else item->widths = NULL;
212 update_item_bbox(item);
213 make_canvas_item_one(ui.cur_layer->group, item);
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);
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;
247 make_canvas_item_one(ui.cur_layer->group, item);
252 undo->type = ITEM_PASTE;
253 undo->layer = ui.cur_layer;
254 undo->itemlist = g_list_copy(ui.selection->items);
256 gtk_selection_data_free(sel_data);
257 update_copy_paste_enabled();
259 update_thickness_buttons();
260 update_color_buttons();
261 update_font_button();
262 update_cursor(); // FIXME: can't know if pointer is within selection!
265 // paste an external image
266 void clipboard_paste_image(GdkPixbuf *pixbuf)
272 get_current_pointer_coords(pt);
273 set_current_page(pt);
275 create_image_from_pixbuf(pixbuf, pt);
278 // work out what format the clipboard data is in, and paste accordingly
279 void clipboard_paste(void)
281 GtkSelectionData *sel_data;
282 GtkClipboard *clipboard;
285 if (ui.cur_layer == NULL) return;
287 ui.cur_item_type = ITEM_PASTE;
288 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
290 sel_data = gtk_clipboard_wait_for_contents(
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);
299 pixbuf = gtk_clipboard_wait_for_image(clipboard);
300 if (pixbuf != NULL) {
301 clipboard_paste_image(pixbuf);