Code

Fixed rendering glitch in bicubic scaler
[inkscape.git] / src / text-context.cpp
index 9645887941f03889edf64ee5187a477040d74d24..0410ab3b4679a7eb830505b5d8924fc7cb562ede 100644 (file)
@@ -48,6 +48,7 @@
 #include "rubberband.h"
 #include "sp-metrics.h"
 #include "context-fns.h"
+#include "verbs.h"
 
 #include "text-editing.h"
 
@@ -289,6 +290,10 @@ sp_text_context_finish(SPEventContext *ec)
 {
     SPTextContext *tc = SP_TEXT_CONTEXT(ec);
 
+    if (ec->desktop) {
+        sp_signal_disconnect_by_data(sp_desktop_canvas(ec->desktop), tc);
+    }
+
     ec->enableGrDrag(false);
 
     tc->style_set_connection.disconnect();
@@ -329,10 +334,6 @@ sp_text_context_finish(SPEventContext *ec)
         gtk_object_destroy(*it);
     }
     tc->text_selection_quads.clear();
-
-    if (ec->desktop) {
-        sp_signal_disconnect_by_data(sp_desktop_canvas(ec->desktop), tc);
-    }
 }
 
 
@@ -435,7 +436,10 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event)
             item_ungrouped = desktop->item_at_point(NR::Point(event->button.x, event->button.y), TRUE);
             if (SP_IS_TEXT(item_ungrouped) || SP_IS_FLOWTEXT(item_ungrouped)) {
                 sp_canvas_item_show(tc->indicator);
-                SP_CTRLRECT(tc->indicator)->setRectangle(sp_item_bbox_desktop(item_ungrouped));
+                NR::Maybe<NR::Rect> ibbox = sp_item_bbox_desktop(item_ungrouped);
+                if (ibbox) {
+                    SP_CTRLRECT(tc->indicator)->setRectangle(*ibbox);
+                }
 
                 ec->cursor_shape = cursor_text_insert_xpm;
                 ec->hot_x = 7;
@@ -472,7 +476,8 @@ sp_text_context_setup_text(SPTextContext *tc)
     SPEventContext *ec = SP_EVENT_CONTEXT(tc);
 
     /* Create <text> */
-    Inkscape::XML::Node *rtext = sp_repr_new("svg:text");
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_EVENT_CONTEXT_DESKTOP(ec)->doc());
+    Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text");
     rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create
 
     /* Set style */
@@ -482,13 +487,13 @@ sp_text_context_setup_text(SPTextContext *tc)
     sp_repr_set_svg_double(rtext, "y", tc->pdoc[NR::Y]);
 
     /* Create <tspan> */
-    Inkscape::XML::Node *rtspan = sp_repr_new("svg:tspan");
+    Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan");
     rtspan->setAttribute("sodipodi:role", "line"); // otherwise, why bother creating the tspan?
     rtext->addChild(rtspan, NULL);
     Inkscape::GC::release(rtspan);
 
     /* Create TEXT */
-    Inkscape::XML::Node *rstring = sp_repr_new_text("");
+    Inkscape::XML::Node *rstring = xml_doc->createTextNode("");
     rtspan->addChild(rstring, NULL);
     Inkscape::GC::release(rstring);
     SPItem *text_item = SP_ITEM(ec->desktop->currentLayer()->appendChildRepr(rtext));
@@ -498,7 +503,8 @@ sp_text_context_setup_text(SPTextContext *tc)
     Inkscape::GC::release(rtext);
     text_item->transform = SP_ITEM(ec->desktop->currentRoot())->getRelativeTransform(ec->desktop->currentLayer());
     text_item->updateRepr();
-    sp_document_done(sp_desktop_document(ec->desktop));
+    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                     _("Create text"));
 }
 
 /**
@@ -536,7 +542,8 @@ insert_uni_char(SPTextContext *const tc)
         tc->text_sel_start = tc->text_sel_end = sp_te_replace(tc->text, tc->text_sel_start, tc->text_sel_end, u);
         sp_text_context_update_cursor(tc);
         sp_text_context_update_text_selection(tc);
-        sp_document_done(sp_desktop_document(tc->desktop));
+        sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM, 
+                         _("Insert Unicode character"));
     }
 }
 
@@ -571,9 +578,9 @@ show_curr_uni_char(SPTextContext *const tc)
             }
         }
         tc->defaultMessageContext()->setF(Inkscape::NORMAL_MESSAGE,
-                                          _("Unicode: %s: %s"), tc->uni, utf8);
+                                          _("Unicode (<b>Enter</b> to finish): %s: %s"), tc->uni, utf8);
     } else {
-        tc->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode: "));
+        tc->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): "));
     }
 }
 
@@ -692,9 +699,12 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                     if (fabs(p1[NR::Y] - tc->p0[NR::Y]) > cursor_height) {
                         // otherwise even one line won't fit; most probably a slip of hand (even if bigger than tolerance)
                         SPItem *ft = create_flowtext_with_internal_frame (desktop, tc->p0, p1);
+                        /* Set style */
+                        sp_desktop_apply_style_tool(SP_EVENT_CONTEXT_DESKTOP(ec), SP_OBJECT_REPR(ft), "tools.text", true);
                         sp_desktop_selection(desktop)->set(ft);
                         ec->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created."));
-                        sp_document_done(sp_desktop_document(desktop));
+                        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                         _("Create flowed text"));
                     } else {
                         ec->desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is <b>too small</b> for the current font size. Flowed text not created."));
                     }
@@ -805,6 +815,13 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
 
                         /* Neither unimode nor IM consumed key; process text tool shortcuts */
                         switch (group0_keyval) {
+                            case GDK_x:
+                            case GDK_X:
+                                if (MOD__ALT_ONLY) {
+                                    desktop->setToolboxFocusTo ("altx-text");
+                                    return TRUE;
+                                }
+                                break;
                             case GDK_space:
                                 if (MOD__CTRL_ONLY) {
                                     /* No-break space */
@@ -816,20 +833,21 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
                                     ec->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space"));
-                                    sp_document_done(sp_desktop_document(ec->desktop));
+                                    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                     _("Insert no-break space"));
                                     return TRUE;
                                 }
                                 break;
                             case GDK_U:
                             case GDK_u:
-                                if (MOD__CTRL_ONLY) {
+                                if (MOD__CTRL_ONLY || (MOD__CTRL && MOD__SHIFT)) {
                                     if (tc->unimode) {
                                         tc->unimode = false;
                                         ec->defaultMessageContext()->clear();
                                     } else {
                                         tc->unimode = true;
                                         tc->unipos = 0;
-                                        ec->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode: "));
+                                        ec->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): "));
                                     }
                                     if (tc->imc) {
                                         gtk_im_context_reset(tc->imc);
@@ -852,7 +870,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                         sp_repr_css_set_property(css, "font-weight", "normal");
                                     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
                                     sp_repr_css_attr_unref(css);
-                                    sp_document_done(sp_desktop_document(ec->desktop));
+                                    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                     _("Make bold"));
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
                                     return TRUE;
@@ -869,7 +888,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                         sp_repr_css_set_property(css, "font-style", "normal");
                                     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
                                     sp_repr_css_attr_unref(css);
-                                    sp_document_done(sp_desktop_document(ec->desktop));
+                                    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                     _("Make italic"));
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
                                     return TRUE;
@@ -892,35 +912,87 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
 
                             case GDK_Return:
                             case GDK_KP_Enter:
+                            {
                                 if (!tc->text) { // printable key; create text if none (i.e. if nascent_object)
                                     sp_text_context_setup_text(tc);
                                     tc->nascent_object = 0; // we don't need it anymore, having created a real <text>
                                 }
-                                tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+                                
+                                iterator_pair enter_pair;
+                                bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, enter_pair);
+                                tc->text_sel_start = tc->text_sel_end = enter_pair.first;
+                                
                                 tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
+                                
                                 sp_text_context_update_cursor(tc);
                                 sp_text_context_update_text_selection(tc);
-                                sp_document_done(sp_desktop_document(ec->desktop));
+                                sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                 _("New line"));
                                 return TRUE;
+                            }
                             case GDK_BackSpace:
                                 if (tc->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys
-                                    if (tc->text_sel_start == tc->text_sel_end)
+                                    
+                                    bool noSelection = false;
+                                    
+                                       if (tc->text_sel_start == tc->text_sel_end) {
                                         tc->text_sel_start.prevCursorPosition();
-                                    tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+                                        noSelection = true;
+                                    }
+                                       
+                                       iterator_pair bspace_pair;
+                                       bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, bspace_pair);
+                                    
+                                    if (noSelection) {
+                                        if (success) {
+                                            tc->text_sel_start = tc->text_sel_end = bspace_pair.first;
+                                        } else { // nothing deleted
+                                            tc->text_sel_start = tc->text_sel_end = bspace_pair.second;
+                                        }
+                                    } else {
+                                        if (success) {
+                                            tc->text_sel_start = tc->text_sel_end = bspace_pair.first;
+                                        } else { // nothing deleted
+                                            tc->text_sel_start = bspace_pair.first;
+                                            tc->text_sel_end = bspace_pair.second;
+                                        }
+                                    }
+                                    
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
-                                    sp_document_done(sp_desktop_document(ec->desktop));
+                                    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                     _("Backspace"));
                                 }
                                 return TRUE;
                             case GDK_Delete:
                             case GDK_KP_Delete:
                                 if (tc->text) {
-                                    if (tc->text_sel_start == tc->text_sel_end)
+                                    bool noSelection = false;
+                                    
+                                    if (tc->text_sel_start == tc->text_sel_end) {
                                         tc->text_sel_end.nextCursorPosition();
-                                    tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+                                        noSelection = true;
+                                    }
+                                    
+                                    iterator_pair del_pair;
+                                    bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, del_pair);
+                                    
+                                    if (noSelection) {
+                                        tc->text_sel_start = tc->text_sel_end = del_pair.first;
+                                    } else {
+                                        if (success) {
+                                            tc->text_sel_start = tc->text_sel_end = del_pair.first;
+                                        } else { // nothing deleted
+                                            tc->text_sel_start = del_pair.first;
+                                            tc->text_sel_end = del_pair.second;
+                                        }
+                                    }
+                                    
+                                    
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
-                                    sp_document_done(sp_desktop_document(ec->desktop));
+                                    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                                                     _("Delete"));
                                 }
                                 return TRUE;
                             case GDK_Left:
@@ -934,7 +1006,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                             sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(-1, 0));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:left");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:left", SP_VERB_CONTEXT_TEXT, 
+                                                               _("Kern to the left"));
                                     } else {
                                         cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorLeftWithControl
                                                                              : &Inkscape::Text::Layout::iterator::cursorLeft;
@@ -953,7 +1026,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                             sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(1, 0));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:right");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:right", SP_VERB_CONTEXT_TEXT, 
+                                                               _("Kern to the right"));
                                     } else {
                                         cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorRightWithControl
                                                                              : &Inkscape::Text::Layout::iterator::cursorRight;
@@ -972,7 +1046,9 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                             sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, -1));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:up");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:up", SP_VERB_CONTEXT_TEXT, 
+                                                               _("Kern up"));
+
                                     } else {
                                         cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorUpWithControl
                                                                              : &Inkscape::Text::Layout::iterator::cursorUp;
@@ -991,7 +1067,9 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                             sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, 1));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:down");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:down", SP_VERB_CONTEXT_TEXT, 
+                                                               _("Kern down"));
+
                                     } else {
                                         cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorDownWithControl
                                                                              : &Inkscape::Text::Layout::iterator::cursorDown;
@@ -1045,7 +1123,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                         } else {
                                             sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -90);
                                         }
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:ccw");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, 
+                                                               _("Rotate counterclockwise"));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
                                         return TRUE;
@@ -1065,7 +1144,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                         } else {
                                             sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 90);
                                         }
-                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:cw");
+                                        sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, 
+                                                                _("Rotate clockwise"));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
                                         return TRUE;
@@ -1081,13 +1161,17 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -10);
                                             else
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -1);
-                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:dec");
+                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, 
+                                                                    _("Contract line spacing"));
+
                                         } else {
                                             if (MOD__SHIFT)
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -10);
                                             else
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -1);
-                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:dec");
+                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, 
+                                                                    _("Contract letter spacing"));
+
                                         }
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
@@ -1104,13 +1188,17 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 10);
                                             else
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 1);
-                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:inc");
+                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, 
+                                                                    _("Expand line spacing"));
+
                                         } else {
                                             if (MOD__SHIFT)
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 10);
                                             else
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 1);
-                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:inc");
+                                            sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, 
+                                                                    _("Expand letter spacing"));
+
                                         }
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
@@ -1212,7 +1300,8 @@ sp_text_paste_inline(SPEventContext *ec)
                 tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
                 begin = end + 1;
             }
-            sp_document_done(sp_desktop_document(ec->desktop));
+            sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+                             _("Paste text"));
 
             return true;
         }
@@ -1251,9 +1340,21 @@ bool sp_text_delete_selection(SPEventContext *ec)
 
     if (tc->text_sel_start == tc->text_sel_end)
         return false;
-    tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+    
+    iterator_pair pair;
+    bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, pair);
+    
+    
+    if (success) {
+        tc->text_sel_start = tc->text_sel_end = pair.first;
+    } else { // nothing deleted
+        tc->text_sel_start = pair.first;
+        tc->text_sel_end = pair.second;
+    }
+    
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
+    
     return true;
 }
 
@@ -1325,7 +1426,8 @@ sp_text_context_style_set(SPCSSAttr const *css, SPTextContext *tc)
         return false;    // will get picked up by the parent and applied to the whole text object
 
     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
-    sp_document_done(sp_desktop_document(tc->desktop));
+    sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, 
+                     _("Set text style"));
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
 
@@ -1361,8 +1463,9 @@ sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc)
         layout->getSourceOfCharacter(it, &rawptr);
         pos_obj = SP_OBJECT(rawptr);
         if (pos_obj == 0) continue;
-        while (SP_OBJECT_STYLE(pos_obj) == NULL && SP_OBJECT_PARENT(pos_obj))
-            pos_obj = SP_OBJECT_PARENT(pos_obj);   // SPStrings don't have style
+        while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) {
+           pos_obj = SP_OBJECT_PARENT(pos_obj);   // SPStrings don't have style
+        }
         styles_list = g_slist_prepend(styles_list, (gpointer)pos_obj);
     }
 
@@ -1389,6 +1492,10 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
 {
     GdkRectangle im_cursor = { 0, 0, 1, 1 };
 
+    // due to interruptible display, tc may already be destroyed during a display update before
+    // the cursor update (can't do both atomically, alas)
+    if (!tc->desktop) return;
+
     if (tc->text) {
         NR::Point p0, p1;
         sp_te_get_cursor_coords(tc->text, tc->text_sel_end, p0, p1);
@@ -1418,7 +1525,10 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
             SPItem *frame = SP_FLOWTEXT(tc->text)->get_frame (NULL); // first frame only
             if (frame) {
                 sp_canvas_item_show(tc->frame);
-                SP_CTRLRECT(tc->frame)->setRectangle(sp_item_bbox_desktop(frame));
+                NR::Maybe<NR::Rect> frame_bbox = sp_item_bbox_desktop(frame);
+                if (frame_bbox) {
+                    SP_CTRLRECT(tc->frame)->setRectangle(*frame_bbox);
+                }
             }
             SP_EVENT_CONTEXT(tc)->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type flowed text; <b>Enter</b> to start new paragraph."));
         } else {
@@ -1442,6 +1552,10 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
 
 static void sp_text_context_update_text_selection(SPTextContext *tc)
 {
+    // due to interruptible display, tc may already be destroyed during a display update before
+    // the selection update (can't do both atomically, alas)
+    if (!tc->desktop) return;
+
     for (std::vector<SPCanvasItem*>::iterator it = tc->text_selection_quads.begin() ; it != tc->text_selection_quads.end() ; it++) {
         sp_canvas_item_hide(*it);
         gtk_object_destroy(*it);
@@ -1493,6 +1607,8 @@ sp_text_context_forget_text(SPTextContext *tc)
         // the XML editor
         if ( text_repr && sp_repr_parent(text_repr) ) {
             sp_repr_unparent(text_repr);
+            sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, 
+                     _("Remove empty text"));
         }
     }
 }
@@ -1523,7 +1639,8 @@ sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc)
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
 
-    sp_document_done(SP_OBJECT_DOCUMENT(tc->text));
+    sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT, 
+                     _("Type text"));
 }