diff options
author | Havoc Pennington <hp@redhat.com> | 2000-11-03 20:40:57 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2000-11-03 20:40:57 +0000 |
commit | ca83d0a3dcb6660cff67f61fca108b1b02c31859 (patch) | |
tree | e3fc8cfe149cdfaac5adb2750c24c200c38e276a | |
parent | b506b461cb03d4b3aac16f82298a5427f1baf759 (diff) | |
download | gdk-pixbuf-ca83d0a3dcb6660cff67f61fca108b1b02c31859.tar.gz |
Get widgets working on the btree/buffer side. Display of them still
2000-11-03 Havoc Pennington <hp@redhat.com>
Get widgets working on the btree/buffer side. Display of them
still doesn't work.
* gtk/gtktextview.c: start implementing child widget stuff
* gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function
* gtk/gtktextlayout.c: handle embedded widgets
* gtk/gtktextdisplay.c: handle embedded widgets
* gtk/gtktextchild.c: Implement all the child anchor goo
* gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New
function
* gtk/gtktextbtree.c: Add child anchor table to the btree struct
(insert_pixbuf_or_widget_segment): abstract out common portions of
creating a child anchor or a pixbuf segment.
(gtk_text_btree_create_child_anchor): new function
(gtk_text_btree_unregister_child_anchor): new function
* gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the
allocate_child signal on GtkTextLayout
* gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return
values
(gtk_text_iter_get_child_anchor): new function
* gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a
default handler for the changed signal, which calls
gtk_text_buffer_set_modified(), instead of just always emitting
changed then calling set_modified() manually. I guess this is
maybe more flexible. It seems logical.
-rw-r--r-- | ChangeLog | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 37 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 37 | ||||
-rw-r--r-- | gtk/gtkmarshal.list | 1 | ||||
-rw-r--r-- | gtk/gtkmarshalers.list | 1 | ||||
-rw-r--r-- | gtk/gtktextbtree.c | 63 | ||||
-rw-r--r-- | gtk/gtktextbtree.h | 7 | ||||
-rw-r--r-- | gtk/gtktextbuffer.c | 72 | ||||
-rw-r--r-- | gtk/gtktextbuffer.h | 20 | ||||
-rw-r--r-- | gtk/gtktextchild.c | 213 | ||||
-rw-r--r-- | gtk/gtktextchild.h | 29 | ||||
-rw-r--r-- | gtk/gtktextchildprivate.h | 18 | ||||
-rw-r--r-- | gtk/gtktextdisplay.c | 147 | ||||
-rw-r--r-- | gtk/gtktextiter.c | 55 | ||||
-rw-r--r-- | gtk/gtktextiter.h | 3 | ||||
-rw-r--r-- | gtk/gtktextlayout.c | 114 | ||||
-rw-r--r-- | gtk/gtktextlayout.h | 27 | ||||
-rw-r--r-- | gtk/gtktextview.c | 140 |
22 files changed, 970 insertions, 199 deletions
@@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index cde1f062e..aa193e9b6 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,40 @@ +2000-11-03 Havoc Pennington <hp@redhat.com> + + Get widgets working on the btree/buffer side. Display of them + still doesn't work. + + * gtk/gtktextview.c: start implementing child widget stuff + + * gtk/gtktextiter.c (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextlayout.c: handle embedded widgets + + * gtk/gtktextdisplay.c: handle embedded widgets + + * gtk/gtktextchild.c: Implement all the child anchor goo + + * gtk/gtktextbuffer.c (gtk_text_buffer_create_child_anchor): New + function + + * gtk/gtktextbtree.c: Add child anchor table to the btree struct + (insert_pixbuf_or_widget_segment): abstract out common portions of + creating a child anchor or a pixbuf segment. + (gtk_text_btree_create_child_anchor): new function + (gtk_text_btree_unregister_child_anchor): new function + + * gtk/gtkmarshal.list: added VOID:OBJECT,INT,INT for the + allocate_child signal on GtkTextLayout + + * gtk/gtktextiter.c (gtk_text_iter_get_pixbuf): fix bogus return + values + (gtk_text_iter_get_child_anchor): new function + + * gtk/gtktextbuffer.c (gtk_text_buffer_real_changed): Add a + default handler for the changed signal, which calls + gtk_text_buffer_set_modified(), instead of just always emitting + changed then calling set_modified() manually. I guess this is + maybe more flexible. It seems logical. + Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org> * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' diff --git a/gtk/gtkmarshal.list b/gtk/gtkmarshal.list index 3b8624549..5e01c765e 100644 --- a/gtk/gtkmarshal.list +++ b/gtk/gtkmarshal.list @@ -56,6 +56,7 @@ VOID:INT,INT,POINTER VOID:OBJECT VOID:OBJECT,BOXED,BOXED VOID:OBJECT,BOOLEAN +VOID:OBJECT,INT,INT VOID:ENUM,INT VOID:POINTER VOID:POINTER,BOOLEAN diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index 3b8624549..5e01c765e 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -56,6 +56,7 @@ VOID:INT,INT,POINTER VOID:OBJECT VOID:OBJECT,BOXED,BOXED VOID:OBJECT,BOOLEAN +VOID:OBJECT,INT,INT VOID:ENUM,INT VOID:POINTER VOID:POINTER,BOOLEAN diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 3f0f7c2c2..b73ba456c 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -195,6 +195,8 @@ struct _GtkTextBTree { GtkTextLine *end_iter_line; guint end_iter_line_stamp; + + GHashTable *child_anchor_table; }; @@ -417,7 +419,8 @@ gtk_text_btree_new (GtkTextTagTable *table, tree); tree->mark_table = g_hash_table_new (g_str_hash, g_str_equal); - + tree->child_anchor_table = NULL; + /* We don't ref the buffer, since the buffer owns us; * we'd have some circularity issues. The buffer always * lasts longer than the BTree @@ -1053,11 +1056,11 @@ gtk_text_btree_insert (GtkTextIter *iter, } } -void -gtk_text_btree_insert_pixbuf (GtkTextIter *iter, - GdkPixbuf *pixbuf) +static void +insert_pixbuf_or_widget_segment (GtkTextIter *iter, + GtkTextLineSegment *seg) + { - GtkTextLineSegment *seg; GtkTextIter start; GtkTextLineSegment *prevPtr; GtkTextLine *line; @@ -1068,8 +1071,6 @@ gtk_text_btree_insert_pixbuf (GtkTextIter *iter, tree = gtk_text_iter_get_btree (iter); start_byte_offset = gtk_text_iter_get_line_index (iter); - seg = _gtk_pixbuf_segment_new (pixbuf); - prevPtr = gtk_text_line_segment_split (iter); if (prevPtr == NULL) { @@ -1092,11 +1093,54 @@ gtk_text_btree_insert_pixbuf (GtkTextIter *iter, gtk_text_btree_get_iter_at_line (tree, &start, line, start_byte_offset); *iter = start; - gtk_text_iter_next_char (iter); /* skip forward past the pixmap */ + gtk_text_iter_next_char (iter); /* skip forward past the segment */ gtk_text_btree_invalidate_region (tree, &start, iter); } + +void +gtk_text_btree_insert_pixbuf (GtkTextIter *iter, + GdkPixbuf *pixbuf) +{ + GtkTextLineSegment *seg; + + seg = _gtk_pixbuf_segment_new (pixbuf); + + insert_pixbuf_or_widget_segment (iter, seg); +} + +GtkTextChildAnchor* +gtk_text_btree_create_child_anchor (GtkTextIter *iter) +{ + GtkTextLineSegment *seg; + GtkTextBTree *tree; + + seg = _gtk_widget_segment_new (); + + insert_pixbuf_or_widget_segment (iter, seg); + + tree = seg->body.child.tree; + + if (tree->child_anchor_table == NULL) + tree->child_anchor_table = g_hash_table_new (NULL, NULL); + + g_hash_table_insert (tree->child_anchor_table, + seg->body.child.obj, + seg->body.child.obj); + + return seg->body.child.obj; +} + +void +gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor) +{ + GtkTextLineSegment *seg; + seg = anchor->segment; + + g_hash_table_remove (seg->body.child.tree->child_anchor_table, + anchor); +} /* * View stuff @@ -2069,7 +2113,8 @@ copy_segment (GString *string, /* printf (" :%s\n", string->str); */ } - else if (seg->type == >k_text_pixbuf_type) + else if (seg->type == >k_text_pixbuf_type || + seg->type == >k_text_child_type) { gboolean copy = TRUE; diff --git a/gtk/gtktextbtree.h b/gtk/gtktextbtree.h index f5ce91d15..a2229373c 100644 --- a/gtk/gtktextbtree.h +++ b/gtk/gtktextbtree.h @@ -34,7 +34,9 @@ void gtk_text_btree_insert (GtkTextIter *iter, void gtk_text_btree_insert_pixbuf (GtkTextIter *iter, GdkPixbuf *pixbuf); +GtkTextChildAnchor* gtk_text_btree_create_child_anchor (GtkTextIter *iter); +void gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor); /* View stuff */ GtkTextLine *gtk_text_btree_find_line_by_y (GtkTextBTree *tree, @@ -129,6 +131,11 @@ gboolean gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree, GtkTextIter *iter, GtkTextTag *tag); +void gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree, + GtkTextIter *iter, + GtkTextChildAnchor *anchor); + + /* Manipulate marks */ GtkTextMark *gtk_text_btree_set_mark (GtkTextBTree *tree, diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 0c3ded39c..c3fcf25e1 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -93,6 +93,7 @@ static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffe GtkTextTag *tag, const GtkTextIter *start_char, const GtkTextIter *end_char); +static void gtk_text_buffer_real_changed (GtkTextBuffer *buffer); static GtkTextBTree* get_btree (GtkTextBuffer *buffer); @@ -230,6 +231,7 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass) klass->delete_text = gtk_text_buffer_real_delete_text; klass->apply_tag = gtk_text_buffer_real_apply_tag; klass->remove_tag = gtk_text_buffer_real_remove_tag; + klass->changed = gtk_text_buffer_real_changed; } void @@ -401,8 +403,6 @@ gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer, gtk_text_btree_insert (iter, text, len); gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); - - gtk_text_buffer_set_modified (buffer, TRUE); } static void @@ -738,8 +738,6 @@ gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer, gtk_text_buffer_update_primary_selection (buffer); gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); - - gtk_text_buffer_set_modified (buffer, TRUE); } static void @@ -1021,10 +1019,31 @@ gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer, /* FIXME pixbuf-specific signal like insert_text */ gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); +} - gtk_text_buffer_set_modified (buffer, TRUE); +/* + * Child anchor + */ + +GtkTextChildAnchor* +gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer, + GtkTextIter *iter) +{ + GtkTextChildAnchor *anchor; + + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); + g_return_val_if_fail (iter != NULL, NULL); + + anchor = gtk_text_btree_create_child_anchor (iter); + + /* FIXME child-anchor-specific signal */ + + gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); + + return anchor; } + /* * Mark manipulation */ @@ -1350,41 +1369,19 @@ gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer) return gtk_text_buffer_get_mark (buffer, "selection_bound"); } - -GtkTextChildAnchor* -gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer, - const GtkTextIter *where) -{ - /* FIXME: Implement? */ - - return NULL; -} - -void -gtk_text_buffer_move_child_anchor (GtkTextBuffer *buffer, - GtkTextChildAnchor *anchor, - GtkTextIter *where) -{ - - -} - -void -gtk_text_buffer_delete_child_anchor (GtkTextBuffer *buffer, - GtkTextChildAnchor *anchor) -{ - - - -} - void gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextChildAnchor *anchor) { - - + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + g_return_if_fail (iter != NULL); + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); + g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor)); + + gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer), + iter, + anchor); } /** @@ -1473,6 +1470,11 @@ gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer, gtk_text_btree_tag (start, end, tag, FALSE); } +static void +gtk_text_buffer_real_changed (GtkTextBuffer *buffer) +{ + gtk_text_buffer_set_modified (buffer, TRUE); +} static void gtk_text_buffer_emit_tag (GtkTextBuffer *buffer, diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h index 2b60ab56e..c1b5fcdd5 100644 --- a/gtk/gtktextbuffer.h +++ b/gtk/gtktextbuffer.h @@ -78,8 +78,9 @@ struct _GtkTextBufferClass { GtkTextIter *end, gboolean interactive); - /* Only for text changed, marks/tags don't cause this - to be emitted */ + /* Only for text/widgets/pixbuf changed, marks/tags don't cause this + * to be emitted + */ void (* changed) (GtkTextBuffer *buffer); @@ -193,6 +194,10 @@ void gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer, GtkTextIter *iter, GdkPixbuf *pixbuf); +/* Create a child anchor */ +GtkTextChildAnchor *gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer, + GtkTextIter *iter); + /* Mark manipulation */ GtkTextMark *gtk_text_buffer_create_mark (GtkTextBuffer *buffer, const gchar *mark_name, @@ -215,17 +220,6 @@ void gtk_text_buffer_delete_mark_by_name (GtkTextBuffer *buffer, GtkTextMark* gtk_text_buffer_get_insert (GtkTextBuffer *buffer); GtkTextMark* gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer); -/* Child widget anchors */ - -GtkTextChildAnchor* gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer, - const GtkTextIter *where); -void gtk_text_buffer_move_child_anchor (GtkTextBuffer *buffer, - GtkTextChildAnchor *anchor, - GtkTextIter *where); -void gtk_text_buffer_delete_child_anchor (GtkTextBuffer *buffer, - GtkTextChildAnchor *anchor); - - /* efficiently move insert and selection_bound to same location */ void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, const GtkTextIter *where); diff --git a/gtk/gtktextchild.c b/gtk/gtktextchild.c index 2baac1033..88c81267e 100644 --- a/gtk/gtktextchild.c +++ b/gtk/gtktextchild.c @@ -49,6 +49,7 @@ #include "gtktextchild.h" #include "gtktextbtree.h" +#include "gtktextlayout.h" static GtkTextLineSegment * pixbuf_segment_cleanup_func (GtkTextLineSegment *seg, @@ -137,8 +138,35 @@ child_segment_delete_func (GtkTextLineSegment *seg, GtkTextLine *line, gboolean tree_gone) { - _gtk_widget_segment_unref (seg); + GSList *tmp_list; + GSList *copy; + gtk_text_btree_unregister_child_anchor (seg->body.child.obj); + + seg->body.child.tree = NULL; + seg->body.child.line = NULL; + + /* avoid removing widgets while walking the list */ + copy = g_slist_copy (seg->body.child.widgets); + tmp_list = copy; + while (tmp_list != NULL) + { + GtkWidget *child = tmp_list->data; + + gtk_widget_destroy (child); + + tmp_list = g_slist_next (tmp_list); + } + + /* On removal from the widget's parents (GtkTextView), + * the widget should have been removed from the anchor. + */ + g_assert (seg->body.child.widgets == NULL); + + g_slist_free (copy); + + _gtk_widget_segment_unref (seg); + return 0; } @@ -185,7 +213,8 @@ _gtk_widget_segment_new (void) */ seg->char_count = 1; - seg->body.child.ref_count = 1; + seg->body.child.obj = g_object_new (GTK_TYPE_TEXT_CHILD_ANCHOR, NULL); + seg->body.child.obj->segment = seg; seg->body.child.widgets = NULL; seg->body.child.tree = NULL; seg->body.child.line = NULL; @@ -197,21 +226,23 @@ void _gtk_widget_segment_add (GtkTextLineSegment *widget_segment, GtkWidget *child) { - g_assert (widget_segment->type = >k_text_child_type); + g_return_if_fail (widget_segment->type = >k_text_child_type); + g_return_if_fail (widget_segment->body.child.tree != NULL); + g_object_ref (G_OBJECT (child)); + widget_segment->body.child.widgets = g_slist_prepend (widget_segment->body.child.widgets, child); - - g_object_ref (G_OBJECT (child)); } void _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment, GtkWidget *child) { - g_assert (widget_segment->type = >k_text_child_type); - + g_return_if_fail (widget_segment->type = >k_text_child_type); + g_return_if_fail (widget_segment->body.child.tree != NULL); + widget_segment->body.child.widgets = g_slist_remove (widget_segment->body.child.widgets, child); @@ -224,7 +255,7 @@ _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment) { g_assert (widget_segment->type = >k_text_child_type); - widget_segment->body.child.ref_count += 1; + g_object_ref (G_OBJECT (widget_segment->body.child.obj)); } void @@ -232,55 +263,112 @@ _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment) { g_assert (widget_segment->type = >k_text_child_type); - widget_segment->body.child.ref_count -= 1; - - if (widget_segment->body.child.ref_count == 0) - { - GSList *tmp_list; + g_object_unref (G_OBJECT (widget_segment->body.child.obj)); +} - if (widget_segment->body.child.tree == NULL) - g_warning ("widget segment destroyed while still in btree"); +GtkTextLayout* +_gtk_anchored_child_get_layout (GtkWidget *child) +{ + return gtk_object_get_data (GTK_OBJECT (child), "gtk-text-child-anchor-layout"); +} - tmp_list = widget_segment->body.child.widgets; - while (tmp_list) - { - g_object_unref (G_OBJECT (tmp_list->data)); +static void +_gtk_anchored_child_set_layout (GtkWidget *child, + GtkTextLayout *layout) +{ + gtk_object_set_data (GTK_OBJECT (child), + "gtk-text-child-anchor-layout", + layout); +} + +static void gtk_text_child_anchor_init (GtkTextChildAnchor *child_anchor); +static void gtk_text_child_anchor_class_init (GtkTextChildAnchorClass *klass); +static void gtk_text_child_anchor_finalize (GObject *obj); - tmp_list = g_slist_next (tmp_list); - } +static gpointer parent_class = NULL; - g_slist_free (widget_segment->body.child.widgets); +GType +gtk_text_child_anchor_get_type (void) +{ + static GType object_type = 0; - g_free (widget_segment); + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GtkTextChildAnchorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_text_child_anchor_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkTextChildAnchor), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_text_child_anchor_init, + }; + + object_type = g_type_register_static (G_TYPE_OBJECT, + "GtkTextChildAnchor", + &object_info, 0); } + + return object_type; } -void -gtk_text_child_anchor_ref (GtkTextChildAnchor *anchor) +static void +gtk_text_child_anchor_init (GtkTextChildAnchor *child_anchor) { - GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; + child_anchor->segment = NULL; +} - g_return_if_fail (seg->type = >k_text_child_type); - g_return_if_fail (seg->body.child.ref_count > 0); +static void +gtk_text_child_anchor_class_init (GtkTextChildAnchorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); - _gtk_widget_segment_ref (seg); + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gtk_text_child_anchor_finalize; } -void -gtk_text_child_anchor_unref (GtkTextChildAnchor *anchor) +static void +gtk_text_child_anchor_finalize (GObject *obj) { - GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; + GtkTextChildAnchor *anchor; + GSList *tmp_list; + GtkTextLineSegment *seg; + + anchor = GTK_TEXT_CHILD_ANCHOR (obj); - g_return_if_fail (seg->type = >k_text_child_type); - g_return_if_fail (seg->body.child.ref_count > 0); + seg = anchor->segment; + + if (seg->body.child.tree != NULL) + { + g_warning ("Someone removed a reference to a GtkTextChildAnchor " + "they didn't own; the anchor is still in the text buffer " + "and the refcount is 0."); + return; + } + + tmp_list = seg->body.child.widgets; + while (tmp_list) + { + g_object_unref (G_OBJECT (tmp_list->data)); + + tmp_list = g_slist_next (tmp_list); + } + + g_slist_free (seg->body.child.widgets); + + g_free (seg); - _gtk_widget_segment_unref (seg); + anchor->segment = NULL; } GList* gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor) { - GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; + GtkTextLineSegment *seg = anchor->segment; GList *list = NULL; GSList *iter; @@ -303,12 +391,63 @@ gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor) gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor) { - GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; + GtkTextLineSegment *seg = anchor->segment; g_return_val_if_fail (seg->type = >k_text_child_type, TRUE); return seg->body.child.tree == NULL; } +void +gtk_text_child_anchor_register_child (GtkTextChildAnchor *anchor, + GtkWidget *child, + GtkTextLayout *layout) +{ + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); + g_return_if_fail (GTK_IS_WIDGET (child)); + _gtk_anchored_child_set_layout (child, layout); + + _gtk_widget_segment_add (anchor->segment, child); + + gtk_text_child_anchor_queue_resize (anchor, layout); +} + +void +gtk_text_child_anchor_unregister_child (GtkTextChildAnchor *anchor, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (_gtk_anchored_child_get_layout (child) != NULL); + + gtk_text_child_anchor_queue_resize (anchor, + _gtk_anchored_child_get_layout (child)); + + _gtk_anchored_child_set_layout (child, NULL); + + _gtk_widget_segment_remove (anchor->segment, child); +} + +void +gtk_text_child_anchor_queue_resize (GtkTextChildAnchor *anchor, + GtkTextLayout *layout) +{ + GtkTextIter start; + GtkTextIter end; + GtkTextLineSegment *seg; + + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); + + seg = anchor->segment; + + g_return_if_fail (seg->body.child.tree != NULL); + + gtk_text_buffer_get_iter_at_child_anchor (layout->buffer, + &start, anchor); + end = start; + gtk_text_iter_next_char (&end); + + gtk_text_layout_invalidate (layout, &start, &end); +} diff --git a/gtk/gtktextchild.h b/gtk/gtktextchild.h index 5c8dc591f..0b10c91ab 100644 --- a/gtk/gtktextchild.h +++ b/gtk/gtktextchild.h @@ -27,7 +27,7 @@ #ifndef GTK_TEXT_CHILD_H #define GTK_TEXT_CHILD_H -#include <glib.h> +#include <glib-object.h> #ifdef __cplusplus extern "C" { @@ -39,10 +39,31 @@ extern "C" { * views. */ -typedef struct _GtkTextChildAnchor GtkTextChildAnchor; +typedef struct _GtkTextChildAnchor GtkTextChildAnchor; +typedef struct _GtkTextChildAnchorClass GtkTextChildAnchorClass; + +#define GTK_TYPE_TEXT_CHILD_ANCHOR (gtk_text_child_anchor_get_type ()) +#define GTK_TEXT_CHILD_ANCHOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_TEXT_CHILD_ANCHOR, GtkTextChildAnchor)) +#define GTK_TEXT_CHILD_ANCHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TEXT_CHILD_ANCHOR, GtkTextChildAnchorClass)) +#define GTK_IS_TEXT_CHILD_ANCHOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_TEXT_CHILD_ANCHOR)) +#define GTK_IS_TEXT_CHILD_ANCHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TEXT_CHILD_ANCHOR)) +#define GTK_TEXT_CHILD_ANCHOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TEXT_CHILD_ANCHOR, GtkTextChildAnchorClass)) + +struct _GtkTextChildAnchor +{ + GObject parent_instance; + + gpointer segment; +}; + +struct _GtkTextChildAnchorClass +{ + GObjectClass parent_class; + +}; + +GType gtk_text_child_anchor_get_type (void) G_GNUC_CONST; -void gtk_text_child_anchor_ref (GtkTextChildAnchor *anchor); -void gtk_text_child_anchor_unref (GtkTextChildAnchor *anchor); GList* gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor); gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor); diff --git a/gtk/gtktextchildprivate.h b/gtk/gtktextchildprivate.h index 8c19f07c0..24bb908e4 100644 --- a/gtk/gtktextchildprivate.h +++ b/gtk/gtktextchildprivate.h @@ -69,19 +69,21 @@ typedef struct _GtkTextChildBody GtkTextChildBody; struct _GtkTextChildBody { - guint ref_count; + GtkTextChildAnchor *obj; GSList *widgets; GtkTextBTree *tree; GtkTextLine *line; }; -GtkTextLineSegment *_gtk_widget_segment_new (void); -void _gtk_widget_segment_add (GtkTextLineSegment *widget_segment, - GtkWidget *child); -void _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment, - GtkWidget *child); -void _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment); -void _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment); +GtkTextLineSegment *_gtk_widget_segment_new (void); +void _gtk_widget_segment_add (GtkTextLineSegment *widget_segment, + GtkWidget *child); +void _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment, + GtkWidget *child); +void _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment); +void _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment); + +GtkTextLayout* _gtk_anchored_child_get_layout (GtkWidget *child); #ifdef __cplusplus } diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c index 3a103593e..10fd95c56 100644 --- a/gtk/gtktextdisplay.c +++ b/gtk/gtktextdisplay.c @@ -185,7 +185,7 @@ static void render_layout_line (GdkDrawable *drawable, GtkTextRenderState *render_state, PangoLayoutLine *line, - GSList **pixbuf_pointer, + GSList **shaped_pointer, int x, int y, gboolean selected) @@ -272,68 +272,99 @@ render_layout_line (GdkDrawable *drawable, x_off += logical_rect.width; } - else /* Pixbuf segment */ + else /* Pixbuf or widget segment */ { - GtkTextPixbuf *pixbuf = (*pixbuf_pointer)->data; - gint width, height; - GdkRectangle pixbuf_rect, draw_rect; - GdkBitmap *mask = NULL; + GObject *shaped = (*shaped_pointer)->data; - *pixbuf_pointer = (*pixbuf_pointer)->next; - - width = gdk_pixbuf_get_width (pixbuf->pixbuf); - height = gdk_pixbuf_get_height (pixbuf->pixbuf); - - pixbuf_rect.x = x + x_off / PANGO_SCALE; - pixbuf_rect.y = y - height; - pixbuf_rect.width = width; - pixbuf_rect.height = height; - - if (gdk_rectangle_intersect (&pixbuf_rect, &render_state->clip_rect, - &draw_rect)) + *shaped_pointer = (*shaped_pointer)->next; + + if (GDK_IS_PIXBUF (shaped)) { - if (gdk_pixbuf_get_has_alpha (pixbuf->pixbuf)) + gint width, height; + GdkRectangle pixbuf_rect, draw_rect; + GdkPixbuf *pixbuf; + + pixbuf = GDK_PIXBUF (shaped); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + pixbuf_rect.x = x + x_off / PANGO_SCALE; + pixbuf_rect.y = y - height; + pixbuf_rect.width = width; + pixbuf_rect.height = height; + + if (gdk_rectangle_intersect (&pixbuf_rect, &render_state->clip_rect, + &draw_rect)) { - mask = gdk_pixmap_new (drawable, - gdk_pixbuf_get_width (pixbuf->pixbuf), - gdk_pixbuf_get_height (pixbuf->pixbuf), - 1); - - gdk_pixbuf_render_threshold_alpha (pixbuf->pixbuf, mask, - 0, 0, 0, 0, - gdk_pixbuf_get_width (pixbuf->pixbuf), - gdk_pixbuf_get_height (pixbuf->pixbuf), - 128); - + GdkBitmap *mask = NULL; + + if (gdk_pixbuf_get_has_alpha (pixbuf)) + { + mask = gdk_pixmap_new (drawable, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + 1); + + gdk_pixbuf_render_threshold_alpha (pixbuf, mask, + 0, 0, 0, 0, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + 128); + + } + + if (mask) + { + gdk_gc_set_clip_mask (render_state->fg_gc, mask); + gdk_gc_set_clip_origin (render_state->fg_gc, + pixbuf_rect.x, pixbuf_rect.y); + } + + gdk_pixbuf_render_to_drawable (pixbuf, + drawable, + render_state->fg_gc, + draw_rect.x - pixbuf_rect.x, + draw_rect.y - pixbuf_rect.y, + draw_rect.x, draw_rect.y, + draw_rect.width, + draw_rect.height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + + if (mask) + { + gdk_gc_set_clip_rectangle (render_state->fg_gc, + &render_state->clip_rect); + g_object_unref (G_OBJECT (mask)); + } } - if (mask) + x_off += width * PANGO_SCALE; + } + else if (GTK_IS_WIDGET (shaped)) + { + gint width, height; + GdkRectangle draw_rect; + GtkWidget *widget; + + widget = GTK_WIDGET (shaped); + + width = widget->allocation.width; + height = widget->allocation.height; + + if (GTK_WIDGET_DRAWABLE (widget) && + gtk_widget_intersect (widget, + &render_state->clip_rect, + &draw_rect)) { - gdk_gc_set_clip_mask (render_state->fg_gc, mask); - gdk_gc_set_clip_origin (render_state->fg_gc, - pixbuf_rect.x, pixbuf_rect.y); + gtk_widget_draw (widget, &draw_rect); } - gdk_pixbuf_render_to_drawable (pixbuf->pixbuf, - drawable, - render_state->fg_gc, - draw_rect.x - pixbuf_rect.x, - draw_rect.y - pixbuf_rect.y, - draw_rect.x, draw_rect.y, - draw_rect.width, - draw_rect.height, - GDK_RGB_DITHER_NORMAL, - 0, 0); - - if (mask) - { - gdk_gc_set_clip_rectangle (render_state->fg_gc, - &render_state->clip_rect); - g_object_unref (G_OBJECT (mask)); - } + x_off += width * PANGO_SCALE; } - - x_off += width * PANGO_SCALE; + else + g_assert_not_reached (); /* not a pixbuf or widget */ } } } @@ -348,7 +379,7 @@ render_para (GdkDrawable *drawable, int selection_end_index) { PangoRectangle logical_rect; - GSList *pixbuf_pointer = line_display->pixbufs; + GSList *shaped_pointer = line_display->shaped_objects; GSList *tmp_list; PangoAlignment align; PangoLayout *layout = line_display->layout; @@ -431,15 +462,15 @@ render_para (GdkDrawable *drawable, TRUE, x + line_display->left_margin, selection_y, total_width / PANGO_SCALE, selection_height); - render_layout_line (drawable, render_state, line, &pixbuf_pointer, + render_layout_line (drawable, render_state, line, &shaped_pointer, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE, TRUE); } else { - GSList *pixbuf_pointer_tmp = pixbuf_pointer; + GSList *shaped_pointer_tmp = shaped_pointer; - render_layout_line (drawable, render_state, line, &pixbuf_pointer, + render_layout_line (drawable, render_state, line, &shaped_pointer, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE, FALSE); @@ -461,7 +492,7 @@ render_para (GdkDrawable *drawable, logical_rect.width / PANGO_SCALE, selection_height); - render_layout_line (drawable, render_state, line, &pixbuf_pointer_tmp, + render_layout_line (drawable, render_state, line, &shaped_pointer_tmp, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE, TRUE); diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c index 4e5ba2bce..e57855551 100644 --- a/gtk/gtktextiter.c +++ b/gtk/gtktextiter.c @@ -849,22 +849,52 @@ gtk_text_iter_get_pixbuf (const GtkTextIter *iter) { GtkTextRealIter *real; - g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (iter != NULL, NULL); real = gtk_text_iter_make_real (iter); if (real == NULL) - return FALSE; + return NULL; check_invariants (iter); if (real->segment->type != >k_text_pixbuf_type) - return FALSE; + return NULL; else return real->segment->body.pixbuf.pixbuf; } /** + * gtk_text_iter_get_child_anchor: + * @iter: an iterator + * + * If the location pointed to by @iter contains a child anchor, the + * anchor is returned (with no new reference count added). Otherwise, + * NULL is returned. + * + * Return value: the anchor at @iter + **/ +GtkTextChildAnchor* +gtk_text_iter_get_child_anchor (const GtkTextIter *iter) +{ + GtkTextRealIter *real; + + g_return_val_if_fail (iter != NULL, NULL); + + real = gtk_text_iter_make_real (iter); + + if (real == NULL) + return NULL; + + check_invariants (iter); + + if (real->segment->type != >k_text_child_type) + return NULL; + else + return real->segment->body.child.obj; +} + +/** * gtk_text_iter_get_marks: * @iter: an iterator * @@ -3734,6 +3764,25 @@ gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree, } void +gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree, + GtkTextIter *iter, + GtkTextChildAnchor *anchor) +{ + GtkTextLineSegment *seg; + + g_return_if_fail (iter != NULL); + g_return_if_fail (tree != NULL); + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); + + seg = anchor->segment; + + iter_init_from_segment (iter, tree, + seg->body.child.line, seg); + g_assert (seg->body.child.line == gtk_text_iter_get_text_line (iter)); + check_invariants (iter); +} + +void gtk_text_btree_get_last_iter (GtkTextBTree *tree, GtkTextIter *iter) { diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h index 148046cfa..3e649d0b4 100644 --- a/gtk/gtktextiter.h +++ b/gtk/gtktextiter.h @@ -28,6 +28,7 @@ #define GTK_TEXT_ITER_H #include <gtk/gtktexttag.h> +#include <gtk/gtktextchild.h> #ifdef __cplusplus extern "C" { @@ -100,6 +101,8 @@ gchar *gtk_text_iter_get_visible_text (const GtkTextIter *start, GdkPixbuf* gtk_text_iter_get_pixbuf (const GtkTextIter *iter); GSList * gtk_text_iter_get_marks (const GtkTextIter *iter); +GtkTextChildAnchor* gtk_text_iter_get_child_anchor (const GtkTextIter *iter); + /* Return list of tags toggled at this point (toggled_on determines whether the list is of on-toggles or off-toggles) */ GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter, diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 2d590af1a..cba5557b3 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -115,6 +115,7 @@ static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *ap enum { INVALIDATED, CHANGED, + ALLOCATE_CHILD, LAST_SIGNAL }; @@ -188,6 +189,18 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass) GTK_TYPE_INT, GTK_TYPE_INT); + signals[ALLOCATE_CHILD] = + gtk_signal_new ("allocate_child", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkTextLayoutClass, allocate_child), + gtk_marshal_VOID__OBJECT_INT_INT, + GTK_TYPE_NONE, + 3, + GTK_TYPE_OBJECT, + GTK_TYPE_INT, + GTK_TYPE_INT); + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); object_class->destroy = gtk_text_layout_destroy; @@ -1195,7 +1208,7 @@ add_text_attrs (GtkTextLayout *layout, static void add_pixbuf_attrs (GtkTextLayout *layout, GtkTextLineDisplay *display, - GtkTextAttributes *style, + GtkTextAttributes *style, GtkTextLineSegment *seg, PangoAttrList *attrs, gint start) @@ -1218,7 +1231,70 @@ add_pixbuf_attrs (GtkTextLayout *layout, attr->end_index = start + seg->byte_count; pango_attr_list_insert (attrs, attr); - display->pixbufs = g_slist_append (display->pixbufs, pixbuf); + display->shaped_objects = + g_slist_append (display->shaped_objects, pixbuf->pixbuf); +} + +static void +add_child_attrs (GtkTextLayout *layout, + GtkTextLineDisplay *display, + GtkTextAttributes *style, + GtkTextLineSegment *seg, + PangoAttrList *attrs, + gint start) +{ + PangoAttribute *attr; + PangoRectangle logical_rect; + GtkTextChildAnchor *anchor; + gint width, height; + GSList *tmp_list; + + width = 1; + height = 1; + + anchor = seg->body.child.obj; + + tmp_list = seg->body.child.widgets; + while (tmp_list != NULL) + { + GtkWidget *child = tmp_list->data; + + if (_gtk_anchored_child_get_layout (child) == layout) + { + /* Found it */ + GtkRequisition req; + + gtk_widget_get_child_requisition (child, &req); + + width = req.width; + height = req.height; + + display->shaped_objects = + g_slist_append (display->shaped_objects, child); + break; + } + + tmp_list = g_slist_next (tmp_list); + } + + if (tmp_list == NULL) + { + /* No widget at this anchor in this display; + * not an error. + */ + + return; + } + + logical_rect.x = 0; + logical_rect.y = -height * PANGO_SCALE; + logical_rect.width = width * PANGO_SCALE; + logical_rect.height = height * PANGO_SCALE; + + attr = pango_attr_shape_new (&logical_rect, &logical_rect); + attr->start_index = start; + attr->end_index = start + seg->byte_count; + pango_attr_list_insert (attrs, attr); } static void @@ -1266,6 +1342,19 @@ add_cursor (GtkTextLayout *layout, } } +static void +allocate_child_widgets (GtkTextLayout *layout, + GtkTextLineDisplay *display) +{ + +#if 0 + gtk_signal_emit (GTK_OBJECT (layout), + signals[ALLOCATE_CHILD], + child, + x, y); +#endif +} + GtkTextLineDisplay * gtk_text_layout_get_line_display (GtkTextLayout *layout, GtkTextLine *line, @@ -1329,7 +1418,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, { /* Displayable segments */ if (seg->type == >k_text_char_type || - seg->type == >k_text_pixbuf_type) + seg->type == >k_text_pixbuf_type || + seg->type == >k_text_child_type) { gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), &iter, line, @@ -1391,7 +1481,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, add_text_attrs (layout, style, byte_count, attrs, byte_offset - byte_count, size_only); } - else + else if (seg->type == >k_text_pixbuf_type) { add_pixbuf_attrs (layout, display, style, seg, attrs, byte_offset); @@ -1399,6 +1489,18 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, seg->byte_count); byte_offset += seg->byte_count; } + else if (seg->type == >k_text_child_type) + { + add_child_attrs (layout, display, style, + seg, attrs, byte_offset); + memcpy (text + byte_offset, gtk_text_unknown_char_utf8, + seg->byte_count); + byte_offset += seg->byte_count; + } + else + { + g_assert_not_reached (); + } } release_style (layout, style); @@ -1476,6 +1578,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, layout->one_display_cache = display; + allocate_child_widgets (layout, display); + return display; } @@ -1491,7 +1595,7 @@ gtk_text_layout_free_line_display (GtkTextLayout *layout, { g_slist_foreach (display->cursors, (GFunc)g_free, NULL); g_slist_free (display->cursors); - g_slist_free (display->pixbufs); + g_slist_free (display->shaped_objects); } g_free (display); diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h index a4eb5858f..04ae9c0c7 100644 --- a/gtk/gtktextlayout.h +++ b/gtk/gtktextlayout.h @@ -153,7 +153,7 @@ struct _GtkTextLayout /* Whether we are allowed to wrap right now */ gint wrap_loop_count; - + /* Whether to show the insertion cursor */ guint cursor_visible : 1; }; @@ -185,7 +185,13 @@ struct _GtkTextLayoutClass void (*free_line_data) (GtkTextLayout *layout, GtkTextLine *line, GtkTextLineData *line_data); + + void (*allocate_child) (GtkTextLayout *layout, + GtkWidget *child, + gint x, + gint y); }; + struct _GtkTextAttrAppearance { PangoAttribute attr; @@ -203,8 +209,8 @@ struct _GtkTextLineDisplay { PangoLayout *layout; GSList *cursors; - GSList *pixbufs; - + GSList *shaped_objects; + GtkTextDirection direction; gint width; /* Width of layout */ @@ -334,9 +340,22 @@ void gtk_text_layout_move_iter_visually (GtkTextLayout *layout, GtkTextIter *iter, gint count); -void gtk_text_layout_spew (GtkTextLayout *layout); +/* Don't use these. Use gtk_text_view_add_child_at_anchor(). + * These functions are defined in gtktextchild.c, but here + * since they are semi-public and require GtkTextLayout to + * be declared. + */ +void gtk_text_child_anchor_register_child (GtkTextChildAnchor *anchor, + GtkWidget *child, + GtkTextLayout *layout); +void gtk_text_child_anchor_unregister_child (GtkTextChildAnchor *anchor, + GtkWidget *child); + +void gtk_text_child_anchor_queue_resize (GtkTextChildAnchor *anchor, + GtkTextLayout *layout); +void gtk_text_layout_spew (GtkTextLayout *layout); #ifdef __cplusplus } diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 3f6c934fa..db43d8d36 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -35,7 +35,6 @@ #include "gtktextview.h" #include "gtkimmulticontext.h" #include "gdk/gdkkeysyms.h" -#include "gtktexttypes.h" #include <string.h> #define FOCUS_EDGE_WIDTH 1 @@ -235,7 +234,8 @@ struct _GtkTextViewChild }; static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child, - GtkTextChildAnchor *anchor); + GtkTextChildAnchor *anchor, + GtkTextLayout *layout); static GtkTextViewChild* text_view_child_new_window (GtkWidget *child, GtkTextWindowType type, gint x, @@ -244,7 +244,6 @@ static void text_view_child_free (GtkTextViewChild *child static void text_view_child_realize (GtkTextView *text_view, GtkTextViewChild *child); -static void text_view_child_unrealize (GtkTextViewChild *child); struct _GtkTextWindow { @@ -278,7 +277,8 @@ static void text_window_get_allocation (GtkTextWindow *win, GdkRectangle *rect); -enum { +enum +{ TARGET_STRING, TARGET_TEXT, TARGET_COMPOUND_TEXT, @@ -708,7 +708,7 @@ gtk_text_view_new_with_buffer (GtkTextBuffer *buffer) } void -gtk_text_view_set_buffer (GtkTextView *text_view, +gtk_text_view_set_buffer (GtkTextView *text_view, GtkTextBuffer *buffer) { g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); @@ -719,6 +719,27 @@ gtk_text_view_set_buffer (GtkTextView *text_view, if (text_view->buffer != NULL) { + /* Destroy all anchored children */ + GSList *tmp_list; + GSList *copy; + + copy = g_slist_copy (text_view->children); + tmp_list = copy; + while (tmp_list != NULL) + { + GtkTextViewChild *vc = tmp_list->data; + + if (vc->anchor) + { + gtk_widget_destroy (vc->widget); + /* vc may now be invalid! */ + } + + tmp_list = g_slist_next (tmp_list); + } + + g_slist_free (copy); + gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer), gtk_text_view_mark_set_handler, text_view); gtk_object_unref (GTK_OBJECT (text_view->buffer)); @@ -1251,7 +1272,8 @@ gtk_text_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { GtkTextView *text_view; - + GSList *tmp_list; + text_view = GTK_TEXT_VIEW (widget); requisition->width = text_view->text_window->requisition.width + FOCUS_EDGE_WIDTH * 2; @@ -1268,6 +1290,69 @@ gtk_text_view_size_request (GtkWidget *widget, if (text_view->bottom_window) requisition->height += text_view->bottom_window->requisition.height; + + tmp_list = text_view->children; + while (tmp_list != NULL) + { + GtkTextViewChild *child = tmp_list->data; + + if (child->anchor) + { + GtkRequisition child_req; + GtkRequisition old_req; + + old_req = child->widget->requisition; + + gtk_widget_size_request (child->widget, &child_req); + + if (text_view->layout && + (old_req.width != child_req.width || + old_req.height != child_req.height)) + gtk_text_child_anchor_queue_resize (child->anchor, + text_view->layout); + } + else + { + + } + + tmp_list = g_slist_next (tmp_list); + } +} + +static void +gtk_text_view_allocate_children (GtkTextView *text_view) +{ + GSList *tmp_list; + + return; + + tmp_list = text_view->children; + while (tmp_list != NULL) + { + GtkTextViewChild *child = tmp_list->data; + + if (child->anchor) + { + /* We need to force-validate the regions containing + * children. + */ + GtkTextIter child_loc; + gtk_text_buffer_get_iter_at_child_anchor (text_view->buffer, + &child_loc, + child->anchor); + + gtk_text_layout_validate_yrange (text_view->layout, + &child_loc, + 0, 1); + } + else + { + + } + + tmp_list = g_slist_next (tmp_list); + } } static void @@ -1285,7 +1370,8 @@ gtk_text_view_size_allocate (GtkWidget *widget, GdkRectangle right_rect; GdkRectangle top_rect; GdkRectangle bottom_rect; - + GSList *tmp_list; + text_view = GTK_TEXT_VIEW (widget); widget->allocation = *allocation; @@ -1383,6 +1469,8 @@ gtk_text_view_size_allocate (GtkWidget *widget, gtk_text_layout_set_screen_width (text_view->layout, SCREEN_WIDTH (text_view)); + gtk_text_view_allocate_children (text_view); + gtk_text_view_validate_onscreen (text_view); gtk_text_view_scroll_calc_now (text_view); @@ -1603,7 +1691,7 @@ static void gtk_text_view_unrealize (GtkWidget *widget) { GtkTextView *text_view; - + text_view = GTK_TEXT_VIEW (widget); if (text_view->first_validate_idle) @@ -1617,7 +1705,7 @@ gtk_text_view_unrealize (GtkWidget *widget) g_source_remove (text_view->incremental_validate_idle); text_view->incremental_validate_idle = 0; } - + text_window_unrealize (text_view->text_window); if (text_view->left_window) @@ -2242,7 +2330,7 @@ gtk_text_view_remove (GtkContainer *container, } g_assert (iter != NULL); /* be sure we had the child in the list */ - + text_view->children = g_slist_remove (text_view->children, vc); gtk_widget_unparent (vc->widget); @@ -4187,22 +4275,25 @@ gtk_text_view_set_text_window_size (GtkTextView *text_view, static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child, - GtkTextChildAnchor *anchor) + GtkTextChildAnchor *anchor, + GtkTextLayout *layout) { GtkTextViewChild *vc; - + vc = g_new (GtkTextViewChild, 1); vc->widget = child; vc->anchor = anchor; g_object_ref (G_OBJECT (vc->widget)); - gtk_text_child_anchor_ref (vc->anchor); + g_object_ref (G_OBJECT (vc->anchor)); gtk_object_set_data (GTK_OBJECT (child), "gtk-text-view-child", vc); + gtk_text_child_anchor_register_child (anchor, child, layout); + return vc; } @@ -4235,9 +4326,15 @@ text_view_child_free (GtkTextViewChild *child) gtk_object_remove_data (GTK_OBJECT (child->widget), "gtk-text-view-child"); - g_object_unref (G_OBJECT (child->widget)); - gtk_text_child_anchor_unref (child->anchor); + if (child->anchor) + { + gtk_text_child_anchor_unregister_child (child->anchor, + child->widget); + g_object_unref (G_OBJECT (child->anchor)); + } + g_object_unref (G_OBJECT (child->widget)); + g_free (child); } @@ -4260,12 +4357,6 @@ text_view_child_realize (GtkTextView *text_view, } static void -text_view_child_unrealize (GtkTextViewChild *vc) -{ - gtk_widget_unrealize (vc->widget); -} - -static void add_child (GtkTextView *text_view, GtkTextViewChild *vc) { @@ -4295,10 +4386,13 @@ gtk_text_view_add_child_at_anchor (GtkTextView *text_view, g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); g_return_if_fail (GTK_IS_WIDGET (child)); - g_return_if_fail (anchor != NULL); + g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor)); g_return_if_fail (child->parent == NULL); - vc = text_view_child_new_anchored (child, anchor); + gtk_text_view_ensure_layout (text_view); + + vc = text_view_child_new_anchored (child, anchor, + text_view->layout); add_child (text_view, vc); } |