2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* code ported from gedit */
21 /* This is for my patient girlfirend Regina */
25 #include "claws-features.h"
30 #include <string.h> /* for strlen */
31 #include <stdlib.h> /* for mbstowcs */
35 #include "prefs_common.h"
37 typedef struct _UndoInfo UndoInfo;
45 gfloat window_position;
52 gchar *pre_wrap_content;
58 static void undo_free_list (GList **list_pointer);
59 static void undo_check_size (UndoMain *undostruct);
60 static gint undo_merge (GList *list,
65 static void undo_add (const gchar *text,
69 UndoMain *undostruct);
70 static gint undo_get_selection (GtkTextView *textview,
73 static void undo_insert_text_cb (GtkTextBuffer *textbuf,
77 UndoMain *undostruct);
78 static void undo_delete_text_cb (GtkTextBuffer *textbuf,
81 UndoMain *undostruct);
83 static void undo_paste_clipboard_cb (GtkTextView *textview,
84 UndoMain *undostruct);
86 void undo_undo (UndoMain *undostruct);
87 void undo_redo (UndoMain *undostruct);
90 UndoMain *undo_init(GtkWidget *text)
93 GtkTextView *textview = GTK_TEXT_VIEW(text);
94 GtkTextBuffer *textbuf = gtk_text_view_get_buffer(textview);
96 cm_return_val_if_fail(text != NULL, NULL);
98 undostruct = g_new0(UndoMain, 1);
99 undostruct->textview = textview;
100 undostruct->undo = NULL;
101 undostruct->redo = NULL;
102 undostruct->paste = 0;
103 undostruct->undo_state = FALSE;
104 undostruct->redo_state = FALSE;
106 g_signal_connect(G_OBJECT(textbuf), "insert-text",
107 G_CALLBACK(undo_insert_text_cb), undostruct);
108 g_signal_connect(G_OBJECT(textbuf), "delete-range",
109 G_CALLBACK(undo_delete_text_cb), undostruct);
110 g_signal_connect(G_OBJECT(textview), "paste-clipboard",
111 G_CALLBACK(undo_paste_clipboard_cb), undostruct);
116 void undo_destroy (UndoMain *undostruct)
118 undo_free_list(&undostruct->undo);
119 undo_free_list(&undostruct->redo);
123 static UndoInfo *undo_object_new(gchar *text, gint start_pos, gint end_pos,
124 UndoAction action, gfloat window_position)
127 undoinfo = g_new (UndoInfo, 1);
128 undoinfo->text = text;
129 undoinfo->start_pos = start_pos;
130 undoinfo->end_pos = end_pos;
131 undoinfo->action = action;
132 undoinfo->window_position = window_position;
136 static void undo_object_free(UndoInfo *undo)
144 * @list_pointer: list to be freed
146 * frees and undo structure list
148 static void undo_free_list(GList **list_pointer)
151 GList *cur, *list = *list_pointer;
153 if (list == NULL) return;
155 for (cur = list; cur != NULL; cur = cur->next) {
156 undo = (UndoInfo *)cur->data;
157 undo_object_free(undo);
161 *list_pointer = NULL;
164 void undo_set_change_state_func(UndoMain *undostruct, UndoChangeStateFunc func,
167 cm_return_if_fail(undostruct != NULL);
169 undostruct->change_state_func = func;
170 undostruct->change_state_data = data;
175 * @compose: document to check
177 * Checks that the size of compose->undo does not excede settings->undo_levels and
178 * frees any undo level above sett->undo_level.
181 static void undo_check_size(UndoMain *undostruct)
186 if (prefs_common.undolevels < 1) return;
188 /* No need to check for the redo list size since the undo
189 list gets freed on any call to compose_undo_add */
190 length = g_list_length(undostruct->undo);
191 if (length >= prefs_common.undolevels && prefs_common.undolevels > 0) {
192 last_undo = (UndoInfo *)g_list_last(undostruct->undo)->data;
193 undostruct->undo = g_list_remove(undostruct->undo, last_undo);
194 undo_object_free(last_undo);
205 * This function tries to merge the undo object at the top of
206 * the stack with a new set of data. So when we undo for example
207 * typing, we can undo the whole word and not each letter by itself
209 * Return Value: TRUE is merge was sucessful, FALSE otherwise
211 static gint undo_merge(GList *list, guint start_pos, guint end_pos,
212 gint action, const guchar *text)
217 /* This are the cases in which we will NOT merge :
218 1. if (last_undo->mergeable == FALSE)
219 [mergeable = FALSE when the size of the undo data was not 1.
220 or if the data was size = 1 but = '\n' or if the undo object
221 has been "undone" already ]
222 2. The size of text is not 1
223 3. If the new merging data is a '\n'
224 4. If the last char of the undo_last data is a space/tab
225 and the new char is not a space/tab ( so that we undo
226 words and not chars )
227 5. If the type (action) of undo is different from the last one
230 if (list == NULL) return FALSE;
232 last_undo = list->data;
234 if (!last_undo->mergeable) return FALSE;
236 if (end_pos - start_pos != 1 ||
238 action != last_undo->action ||
239 action == UNDO_ACTION_REPLACE_INSERT ||
240 action == UNDO_ACTION_REPLACE_DELETE) {
241 last_undo->mergeable = FALSE;
245 if (action == UNDO_ACTION_DELETE) {
246 if (last_undo->start_pos != end_pos &&
247 last_undo->start_pos != start_pos) {
248 last_undo->mergeable = FALSE;
250 } else if (last_undo->start_pos == start_pos) {
251 /* Deleted with the delete key */
252 temp_string = g_strdup_printf("%s%s", last_undo->text, text);
253 last_undo->end_pos++;
254 g_free(last_undo->text);
255 last_undo->text = temp_string;
257 /* Deleted with the backspace key */
258 temp_string = g_strdup_printf("%s%s", text, last_undo->text);
259 last_undo->start_pos = start_pos;
260 g_free(last_undo->text);
261 last_undo->text = temp_string;
263 } else if (action == UNDO_ACTION_INSERT) {
264 if (last_undo->end_pos != start_pos) {
265 last_undo->mergeable = FALSE;
268 temp_string = g_strdup_printf("%s%s", last_undo->text, text);
269 g_free(last_undo->text);
270 last_undo->end_pos = end_pos;
271 last_undo->text = temp_string;
274 debug_print("Unknown action [%i] inside undo merge encountered", action);
284 * @action: either UNDO_ACTION_INSERT or UNDO_ACTION_DELETE
286 * @view: The view so that we save the scroll bar position.
288 * Adds text to the undo stack. It also performs test to limit the number
289 * of undo levels and deltes the redo list
292 static void undo_add(const gchar *text,
293 gint start_pos, gint end_pos,
294 UndoAction action, UndoMain *undostruct)
299 cm_return_if_fail(text != NULL);
300 cm_return_if_fail(end_pos >= start_pos);
302 undo_free_list(&undostruct->redo);
304 /* Set the redo sensitivity */
305 undostruct->change_state_func(undostruct,
306 UNDO_STATE_UNCHANGED, UNDO_STATE_FALSE,
307 undostruct->change_state_data);
309 if (undostruct->paste != 0) {
310 if (action == UNDO_ACTION_INSERT)
311 action = UNDO_ACTION_REPLACE_INSERT;
313 action = UNDO_ACTION_REPLACE_DELETE;
314 undostruct->paste = undostruct->paste + 1;
315 if (undostruct->paste == 3)
316 undostruct->paste = 0;
319 if (undo_merge(undostruct->undo, start_pos, end_pos, action, text))
322 undo_check_size(undostruct);
324 vadj = GTK_ADJUSTMENT(gtk_text_view_get_vadjustment(
325 GTK_TEXT_VIEW(undostruct->textview)));
326 undoinfo = undo_object_new(g_strdup(text), start_pos, end_pos, action,
327 gtk_adjustment_get_value(vadj));
329 if (end_pos - start_pos != 1 || text[0] == '\n')
330 undoinfo->mergeable = FALSE;
332 undoinfo->mergeable = TRUE;
334 undostruct->undo = g_list_prepend(undostruct->undo, undoinfo);
336 undostruct->change_state_func(undostruct,
337 UNDO_STATE_TRUE, UNDO_STATE_UNCHANGED,
338 undostruct->change_state_data);
346 * Executes an undo request on the current document
348 void undo_undo(UndoMain *undostruct)
351 GtkTextView *textview;
352 GtkTextBuffer *buffer;
353 GtkTextIter iter, start_iter, end_iter;
356 cm_return_if_fail(undostruct != NULL);
358 if (undostruct->undo == NULL) return;
360 /* The undo data we need is always at the top op the
361 stack. So, therefore, the first one */
362 undoinfo = (UndoInfo *)undostruct->undo->data;
363 cm_return_if_fail(undoinfo != NULL);
364 undoinfo->mergeable = FALSE;
365 undostruct->redo = g_list_prepend(undostruct->redo, undoinfo);
366 undostruct->undo = g_list_remove(undostruct->undo, undoinfo);
368 textview = undostruct->textview;
369 buffer = gtk_text_view_get_buffer(textview);
371 undo_block(undostruct);
373 /* Check if there is a selection active */
374 mark = gtk_text_buffer_get_insert(buffer);
375 gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
376 gtk_text_buffer_place_cursor(buffer, &iter);
378 /* Move the view (scrollbars) to the correct position */
379 gtk_adjustment_set_value
380 (GTK_ADJUSTMENT(gtk_text_view_get_vadjustment(textview)),
381 undoinfo->window_position);
383 switch (undoinfo->action) {
384 case UNDO_ACTION_DELETE:
385 gtk_text_buffer_get_iter_at_offset(buffer, &iter, undoinfo->start_pos);
386 gtk_text_buffer_insert(buffer, &iter, undoinfo->text, -1);
388 case UNDO_ACTION_INSERT:
389 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
390 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, undoinfo->end_pos);
391 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
393 case UNDO_ACTION_REPLACE_INSERT:
394 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
395 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, undoinfo->end_pos);
396 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
397 /* "pull" previous matching DELETE data structure from the list */
398 if (undostruct->undo){
399 undoinfo = (UndoInfo *)undostruct->undo->data;
400 undostruct->redo = g_list_prepend(undostruct->redo, undoinfo);
401 undostruct->undo = g_list_remove(undostruct->undo, undoinfo);
402 cm_return_if_fail(undoinfo != NULL);
403 cm_return_if_fail(undoinfo->action == UNDO_ACTION_REPLACE_DELETE);
404 gtk_text_buffer_insert(buffer, &start_iter, undoinfo->text, -1);
407 case UNDO_ACTION_REPLACE_DELETE:
408 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
409 gtk_text_buffer_insert(buffer, &start_iter, undoinfo->text, -1);
410 /* "pull" previous matching INSERT data structure from the list */
411 if (undostruct->undo){
412 undoinfo = (UndoInfo *)undostruct->undo->data;
413 undostruct->redo = g_list_prepend(undostruct->redo, undoinfo);
414 undostruct->undo = g_list_remove(undostruct->undo, undoinfo);
415 cm_return_if_fail(undoinfo != NULL);
416 cm_return_if_fail(undoinfo->action == UNDO_ACTION_REPLACE_INSERT);
417 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
418 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, undoinfo->end_pos);
419 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
423 g_assert_not_reached();
427 undostruct->change_state_func(undostruct,
428 UNDO_STATE_UNCHANGED, UNDO_STATE_TRUE,
429 undostruct->change_state_data);
431 if (undostruct->undo == NULL)
432 undostruct->change_state_func(undostruct,
434 UNDO_STATE_UNCHANGED,
435 undostruct->change_state_data);
437 undo_unblock(undostruct);
445 * executes a redo request on the current document
447 void undo_redo(UndoMain *undostruct)
450 GtkTextView *textview;
451 GtkTextBuffer *buffer;
452 GtkTextIter iter, start_iter, end_iter;
455 cm_return_if_fail(undostruct != NULL);
457 if (undostruct->redo == NULL) return;
459 redoinfo = (UndoInfo *)undostruct->redo->data;
460 cm_return_if_fail (redoinfo != NULL);
461 undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
462 undostruct->redo = g_list_remove(undostruct->redo, redoinfo);
464 textview = undostruct->textview;
465 buffer = gtk_text_view_get_buffer(textview);
467 undo_block(undostruct);
469 /* Check if there is a selection active */
470 mark = gtk_text_buffer_get_insert(buffer);
471 gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
472 gtk_text_buffer_place_cursor(buffer, &iter);
474 /* Move the view to the right position. */
475 gtk_adjustment_set_value(gtk_text_view_get_vadjustment(textview),
476 redoinfo->window_position);
478 switch (redoinfo->action) {
479 case UNDO_ACTION_INSERT:
480 gtk_text_buffer_get_iter_at_offset(buffer, &iter, redoinfo->start_pos);
481 gtk_text_buffer_insert(buffer, &iter, redoinfo->text, -1);
483 case UNDO_ACTION_DELETE:
484 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, redoinfo->start_pos);
485 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, redoinfo->end_pos);
486 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
488 case UNDO_ACTION_REPLACE_DELETE:
489 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, redoinfo->start_pos);
490 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, redoinfo->end_pos);
491 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
492 debug_print("UNDO_ACTION_REPLACE %s\n", redoinfo->text);
493 /* "pull" previous matching INSERT data structure from the list */
494 redoinfo = (UndoInfo *)undostruct->redo->data;
495 cm_return_if_fail(redoinfo != NULL);
496 undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
497 undostruct->redo = g_list_remove(undostruct->redo, redoinfo);
498 cm_return_if_fail(redoinfo->action == UNDO_ACTION_REPLACE_INSERT);
499 gtk_text_buffer_insert(buffer, &start_iter, redoinfo->text, -1);
501 case UNDO_ACTION_REPLACE_INSERT:
502 gtk_text_buffer_get_iter_at_offset(buffer, &iter, redoinfo->start_pos);
503 gtk_text_buffer_insert(buffer, &iter, redoinfo->text, -1);
504 /* "pull" previous matching DELETE structure from the list */
505 redoinfo = (UndoInfo *)undostruct->redo->data;
506 /* Do nothing if we redo from a middle-click button
507 * and next action is not UNDO_ACTION_REPLACE_DELETE */
508 if (redoinfo && redoinfo->action == UNDO_ACTION_REPLACE_DELETE) {
509 undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
510 undostruct->redo = g_list_remove(undostruct->redo, redoinfo);
511 gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, redoinfo->start_pos);
512 gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, redoinfo->end_pos);
513 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
517 g_assert_not_reached();
521 undostruct->change_state_func(undostruct,
522 UNDO_STATE_TRUE, UNDO_STATE_UNCHANGED,
523 undostruct->change_state_data);
525 if (undostruct->redo == NULL)
526 undostruct->change_state_func(undostruct,
527 UNDO_STATE_UNCHANGED,
529 undostruct->change_state_data);
531 undo_unblock(undostruct);
534 void undo_block(UndoMain *undostruct)
536 GtkTextBuffer *buffer;
538 cm_return_if_fail(GTK_IS_TEXT_VIEW(undostruct->textview));
540 buffer = gtk_text_view_get_buffer(undostruct->textview);
541 g_signal_handlers_block_by_func(buffer, undo_insert_text_cb, undostruct);
542 g_signal_handlers_block_by_func(buffer, undo_delete_text_cb, undostruct);
543 g_signal_handlers_block_by_func(buffer, undo_paste_clipboard_cb,
547 void undo_unblock(UndoMain *undostruct)
549 GtkTextBuffer *buffer;
551 cm_return_if_fail(GTK_IS_TEXT_VIEW(undostruct->textview));
553 buffer = gtk_text_view_get_buffer(undostruct->textview);
554 g_signal_handlers_unblock_by_func(buffer, undo_insert_text_cb, undostruct);
555 g_signal_handlers_unblock_by_func(buffer, undo_delete_text_cb, undostruct);
556 g_signal_handlers_unblock_by_func(buffer, undo_paste_clipboard_cb,
560 /* Init the WrapInfo structure */
561 static void init_wrap_undo(UndoMain *undostruct)
563 GtkTextBuffer *buffer;
564 GtkTextIter start, end;
566 cm_return_if_fail(undostruct != NULL);
567 cm_return_if_fail(undostruct->wrap_info == NULL);
569 undostruct->wrap_info = g_new0(UndoWrap, 1);
571 /* Save the whole buffer as original contents. We'll retain the
572 * changed region when exiting wrap mode.
574 buffer = gtk_text_view_get_buffer(undostruct->textview);
575 gtk_text_buffer_get_start_iter(buffer, &start);
576 gtk_text_buffer_get_end_iter(buffer, &end);
577 undostruct->wrap_info->pre_wrap_content
578 = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
580 undostruct->wrap_info->lock = 0;
582 /* start_pos == -1 means nothing changed yet. */
583 undostruct->wrap_info->start_pos = -1;
584 undostruct->wrap_info->end_pos = -1;
585 undostruct->wrap_info->len_change = 0;
588 static void end_wrap_undo(UndoMain *undostruct)
590 GtkTextBuffer *buffer;
591 GtkTextIter start, end;
592 gchar *old_contents = NULL;
593 gchar *cur_contents = NULL;
594 gchar *new_contents = NULL;
596 cm_return_if_fail(undostruct != NULL);
597 cm_return_if_fail(undostruct->wrap_info != NULL);
599 /* If start_pos is still == -1, it means nothing changed. */
600 if (undostruct->wrap_info->start_pos == -1)
603 cm_return_if_fail(undostruct->wrap_info->end_pos > undostruct->wrap_info->start_pos);
604 cm_return_if_fail(undostruct->wrap_info->end_pos - undostruct->wrap_info->len_change > undostruct->wrap_info->start_pos);
606 /* get the whole new (wrapped) contents */
607 buffer = gtk_text_view_get_buffer(undostruct->textview);
608 gtk_text_buffer_get_start_iter(buffer, &start);
609 gtk_text_buffer_get_end_iter(buffer, &end);
610 cur_contents = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
612 debug_print("wrapping done from %d to %d, len change: %d\n",
613 undostruct->wrap_info->start_pos,
614 undostruct->wrap_info->end_pos,
615 undostruct->wrap_info->len_change);
617 /* keep the relevant old unwrapped part, which is what
618 * was between start_pos & end_pos - len_change
620 old_contents = g_utf8_substring(
621 undostruct->wrap_info->pre_wrap_content,
622 undostruct->wrap_info->start_pos,
623 undostruct->wrap_info->end_pos
624 - undostruct->wrap_info->len_change);
626 /* and get the changed contents, from start_pos to end_pos. */
627 new_contents = g_utf8_substring(
629 undostruct->wrap_info->start_pos,
630 undostruct->wrap_info->end_pos);
632 /* add the deleted (unwrapped) text to the undo pile */
633 undo_add(old_contents,
634 undostruct->wrap_info->start_pos,
635 undostruct->wrap_info->end_pos
636 - undostruct->wrap_info->len_change,
637 UNDO_ACTION_REPLACE_DELETE,
640 /* add the inserted (wrapped) text to the undo pile */
641 undo_add(new_contents,
642 undostruct->wrap_info->start_pos,
643 undostruct->wrap_info->end_pos,
644 UNDO_ACTION_REPLACE_INSERT,
647 g_free(old_contents);
648 g_free(cur_contents);
649 g_free(new_contents);
651 g_free(undostruct->wrap_info->pre_wrap_content);
652 g_free(undostruct->wrap_info);
653 undostruct->wrap_info = NULL;
656 static void update_wrap_undo(UndoMain *undostruct, const gchar *text, int start,
657 int end, UndoAction action)
659 gint len = end - start;
661 /* If we don't yet have a start position, or farther than
664 if (undostruct->wrap_info->start_pos == -1
665 || start < undostruct->wrap_info->start_pos) {
666 undostruct->wrap_info->start_pos = start;
669 if (action == UNDO_ACTION_INSERT) {
670 /* If inserting, the end of the region is at the end of the
671 * change, and the total length of the changed region
674 if (end > undostruct->wrap_info->end_pos) {
675 undostruct->wrap_info->end_pos = end;
677 undostruct->wrap_info->len_change += len;
678 } else if (action == UNDO_ACTION_DELETE) {
679 /* If deleting, the end of the region is at the start of the
680 * change, and the total length of the changed region
683 if (start > undostruct->wrap_info->end_pos) {
684 undostruct->wrap_info->end_pos = start;
686 undostruct->wrap_info->len_change -= len;
690 /* Set wrapping mode, in which changes are agglomerated until
691 * the end of wrapping mode.
693 void undo_wrapping(UndoMain *undostruct, gboolean wrap)
696 /* Start (or go deeper in) wrapping mode */
697 if (undostruct->wrap_info == NULL)
698 init_wrap_undo(undostruct);
699 undostruct->wrap_info->lock++;
700 } else if (undostruct->wrap_info != NULL) {
701 /* exit (& possible stop) one level of wrapping mode */
702 undostruct->wrap_info->lock--;
703 if (undostruct->wrap_info->lock == 0)
704 end_wrap_undo(undostruct);
706 g_warning("undo already out of wrap mode");
710 void undo_insert_text_cb(GtkTextBuffer *textbuf, GtkTextIter *iter,
711 gchar *new_text, gint new_text_length,
712 UndoMain *undostruct)
714 gchar *text_to_insert;
718 if (prefs_common.undolevels <= 0) return;
720 pos = gtk_text_iter_get_offset(iter);
721 Xstrndup_a(text_to_insert, new_text, new_text_length, return);
722 utf8_len = g_utf8_strlen(text_to_insert, -1);
724 if (undostruct->wrap_info != NULL) {
725 update_wrap_undo(undostruct, text_to_insert,
726 pos, pos + utf8_len, UNDO_ACTION_INSERT);
730 debug_print("add:undo add %d-%ld\n", pos, utf8_len);
731 undo_add(text_to_insert, pos, pos + utf8_len,
732 UNDO_ACTION_INSERT, undostruct);
735 void undo_delete_text_cb(GtkTextBuffer *textbuf, GtkTextIter *start,
736 GtkTextIter *end, UndoMain *undostruct)
738 gchar *text_to_delete;
739 gint start_pos, end_pos;
741 if (prefs_common.undolevels <= 0) return;
743 text_to_delete = gtk_text_buffer_get_text(textbuf, start, end, FALSE);
744 if (!text_to_delete || !*text_to_delete) return;
746 start_pos = gtk_text_iter_get_offset(start);
747 end_pos = gtk_text_iter_get_offset(end);
749 if (undostruct->wrap_info != NULL) {
750 update_wrap_undo(undostruct, text_to_delete, start_pos, end_pos, UNDO_ACTION_DELETE);
753 debug_print("del:undo add %d-%d\n", start_pos, end_pos);
754 undo_add(text_to_delete, start_pos, end_pos, UNDO_ACTION_DELETE,
756 g_free(text_to_delete);
759 void undo_paste_clipboard(GtkTextView *textview, UndoMain *undostruct)
761 undo_paste_clipboard_cb(textview, undostruct);
764 static void undo_paste_clipboard_cb(GtkTextView *textview, UndoMain *undostruct)
766 if (prefs_common.undolevels > 0)
767 if (undo_get_selection(textview, NULL, NULL))
768 undostruct->paste = TRUE;
772 * undo_get_selection:
773 * @text: Text to get the selection from
774 * @start: return here the start position of the selection
775 * @end: return here the end position of the selection
777 * Gets the current selection for View
779 * Return Value: TRUE if there is a selection active, FALSE if not
781 static gint undo_get_selection(GtkTextView *textview, guint *start, guint *end)
783 GtkTextBuffer *buffer;
784 GtkTextIter start_iter, end_iter;
785 guint start_pos, end_pos;
787 buffer = gtk_text_view_get_buffer(textview);
788 gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter);
790 start_pos = gtk_text_iter_get_offset(&start_iter);
791 end_pos = gtk_text_iter_get_offset(&end_iter);
793 /* The user can select from end to start too. If so, swap it*/
794 if (end_pos < start_pos) {
798 start_pos = swap_pos;
807 if ((start_pos > 0 || end_pos > 0) && (start_pos != end_pos))