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.
This commit is contained in:
Havoc Pennington 2000-11-03 20:40:57 +00:00 committed by Havoc Pennington
parent b506b461cb
commit ca83d0a3dc
22 changed files with 976 additions and 205 deletions

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -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> Fri Nov 3 08:58:38 2000 Tim Janik <timj@gtk.org>
* gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_' * gtk/gtkobject.c: _g_signal_handlers_destroy() is prefixed with '_'

View File

@ -56,6 +56,7 @@ VOID:INT,INT,POINTER
VOID:OBJECT VOID:OBJECT
VOID:OBJECT,BOXED,BOXED VOID:OBJECT,BOXED,BOXED
VOID:OBJECT,BOOLEAN VOID:OBJECT,BOOLEAN
VOID:OBJECT,INT,INT
VOID:ENUM,INT VOID:ENUM,INT
VOID:POINTER VOID:POINTER
VOID:POINTER,BOOLEAN VOID:POINTER,BOOLEAN

View File

@ -56,6 +56,7 @@ VOID:INT,INT,POINTER
VOID:OBJECT VOID:OBJECT
VOID:OBJECT,BOXED,BOXED VOID:OBJECT,BOXED,BOXED
VOID:OBJECT,BOOLEAN VOID:OBJECT,BOOLEAN
VOID:OBJECT,INT,INT
VOID:ENUM,INT VOID:ENUM,INT
VOID:POINTER VOID:POINTER
VOID:POINTER,BOOLEAN VOID:POINTER,BOOLEAN

View File

@ -195,6 +195,8 @@ struct _GtkTextBTree {
GtkTextLine *end_iter_line; GtkTextLine *end_iter_line;
guint end_iter_line_stamp; guint end_iter_line_stamp;
GHashTable *child_anchor_table;
}; };
@ -417,6 +419,7 @@ gtk_text_btree_new (GtkTextTagTable *table,
tree); tree);
tree->mark_table = g_hash_table_new (g_str_hash, g_str_equal); 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 don't ref the buffer, since the buffer owns us;
* we'd have some circularity issues. The buffer always * we'd have some circularity issues. The buffer always
@ -1053,11 +1056,11 @@ gtk_text_btree_insert (GtkTextIter *iter,
} }
} }
void static void
gtk_text_btree_insert_pixbuf (GtkTextIter *iter, insert_pixbuf_or_widget_segment (GtkTextIter *iter,
GdkPixbuf *pixbuf) GtkTextLineSegment *seg)
{ {
GtkTextLineSegment *seg;
GtkTextIter start; GtkTextIter start;
GtkTextLineSegment *prevPtr; GtkTextLineSegment *prevPtr;
GtkTextLine *line; GtkTextLine *line;
@ -1068,8 +1071,6 @@ gtk_text_btree_insert_pixbuf (GtkTextIter *iter,
tree = gtk_text_iter_get_btree (iter); tree = gtk_text_iter_get_btree (iter);
start_byte_offset = gtk_text_iter_get_line_index (iter); start_byte_offset = gtk_text_iter_get_line_index (iter);
seg = _gtk_pixbuf_segment_new (pixbuf);
prevPtr = gtk_text_line_segment_split (iter); prevPtr = gtk_text_line_segment_split (iter);
if (prevPtr == NULL) 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); gtk_text_btree_get_iter_at_line (tree, &start, line, start_byte_offset);
*iter = start; *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); 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 * View stuff
@ -2069,7 +2113,8 @@ copy_segment (GString *string,
/* printf (" :%s\n", string->str); */ /* printf (" :%s\n", string->str); */
} }
else if (seg->type == &gtk_text_pixbuf_type) else if (seg->type == &gtk_text_pixbuf_type ||
seg->type == &gtk_text_child_type)
{ {
gboolean copy = TRUE; gboolean copy = TRUE;

View File

@ -34,7 +34,9 @@ void gtk_text_btree_insert (GtkTextIter *iter,
void gtk_text_btree_insert_pixbuf (GtkTextIter *iter, void gtk_text_btree_insert_pixbuf (GtkTextIter *iter,
GdkPixbuf *pixbuf); GdkPixbuf *pixbuf);
GtkTextChildAnchor* gtk_text_btree_create_child_anchor (GtkTextIter *iter);
void gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor);
/* View stuff */ /* View stuff */
GtkTextLine *gtk_text_btree_find_line_by_y (GtkTextBTree *tree, 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, GtkTextIter *iter,
GtkTextTag *tag); GtkTextTag *tag);
void gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
GtkTextIter *iter,
GtkTextChildAnchor *anchor);
/* Manipulate marks */ /* Manipulate marks */
GtkTextMark *gtk_text_btree_set_mark (GtkTextBTree *tree, GtkTextMark *gtk_text_btree_set_mark (GtkTextBTree *tree,

View File

@ -93,6 +93,7 @@ static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffe
GtkTextTag *tag, GtkTextTag *tag,
const GtkTextIter *start_char, const GtkTextIter *start_char,
const GtkTextIter *end_char); const GtkTextIter *end_char);
static void gtk_text_buffer_real_changed (GtkTextBuffer *buffer);
static GtkTextBTree* get_btree (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->delete_text = gtk_text_buffer_real_delete_text;
klass->apply_tag = gtk_text_buffer_real_apply_tag; klass->apply_tag = gtk_text_buffer_real_apply_tag;
klass->remove_tag = gtk_text_buffer_real_remove_tag; klass->remove_tag = gtk_text_buffer_real_remove_tag;
klass->changed = gtk_text_buffer_real_changed;
} }
void void
@ -401,8 +403,6 @@ gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
gtk_text_btree_insert (iter, text, len); gtk_text_btree_insert (iter, text, len);
gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
gtk_text_buffer_set_modified (buffer, TRUE);
} }
static void static void
@ -738,8 +738,6 @@ gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
gtk_text_buffer_update_primary_selection (buffer); gtk_text_buffer_update_primary_selection (buffer);
gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
gtk_text_buffer_set_modified (buffer, TRUE);
} }
static void static void
@ -1021,10 +1019,31 @@ gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer,
/* FIXME pixbuf-specific signal like insert_text */ /* FIXME pixbuf-specific signal like insert_text */
gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]); 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 * Mark manipulation
*/ */
@ -1350,41 +1369,19 @@ gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
return gtk_text_buffer_get_mark (buffer, "selection_bound"); 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 void
gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer *buffer, gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer *buffer,
GtkTextIter *iter, GtkTextIter *iter,
GtkTextChildAnchor *anchor) 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); 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 static void
gtk_text_buffer_emit_tag (GtkTextBuffer *buffer, gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,

View File

@ -78,8 +78,9 @@ struct _GtkTextBufferClass {
GtkTextIter *end, GtkTextIter *end,
gboolean interactive); gboolean interactive);
/* Only for text changed, marks/tags don't cause this /* Only for text/widgets/pixbuf changed, marks/tags don't cause this
to be emitted */ * to be emitted
*/
void (* changed) (GtkTextBuffer *buffer); void (* changed) (GtkTextBuffer *buffer);
@ -193,6 +194,10 @@ void gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer,
GtkTextIter *iter, GtkTextIter *iter,
GdkPixbuf *pixbuf); GdkPixbuf *pixbuf);
/* Create a child anchor */
GtkTextChildAnchor *gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
GtkTextIter *iter);
/* Mark manipulation */ /* Mark manipulation */
GtkTextMark *gtk_text_buffer_create_mark (GtkTextBuffer *buffer, GtkTextMark *gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
const gchar *mark_name, 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_insert (GtkTextBuffer *buffer);
GtkTextMark* gtk_text_buffer_get_selection_bound (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 */ /* efficiently move insert and selection_bound to same location */
void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer,
const GtkTextIter *where); const GtkTextIter *where);

View File

@ -49,6 +49,7 @@
#include "gtktextchild.h" #include "gtktextchild.h"
#include "gtktextbtree.h" #include "gtktextbtree.h"
#include "gtktextlayout.h"
static GtkTextLineSegment * static GtkTextLineSegment *
pixbuf_segment_cleanup_func (GtkTextLineSegment *seg, pixbuf_segment_cleanup_func (GtkTextLineSegment *seg,
@ -137,6 +138,33 @@ child_segment_delete_func (GtkTextLineSegment *seg,
GtkTextLine *line, GtkTextLine *line,
gboolean tree_gone) gboolean tree_gone)
{ {
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); _gtk_widget_segment_unref (seg);
return 0; return 0;
@ -185,7 +213,8 @@ _gtk_widget_segment_new (void)
*/ */
seg->char_count = 1; 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.widgets = NULL;
seg->body.child.tree = NULL; seg->body.child.tree = NULL;
seg->body.child.line = NULL; seg->body.child.line = NULL;
@ -197,20 +226,22 @@ void
_gtk_widget_segment_add (GtkTextLineSegment *widget_segment, _gtk_widget_segment_add (GtkTextLineSegment *widget_segment,
GtkWidget *child) GtkWidget *child)
{ {
g_assert (widget_segment->type = &gtk_text_child_type); g_return_if_fail (widget_segment->type = &gtk_text_child_type);
g_return_if_fail (widget_segment->body.child.tree != NULL);
g_object_ref (G_OBJECT (child));
widget_segment->body.child.widgets = widget_segment->body.child.widgets =
g_slist_prepend (widget_segment->body.child.widgets, g_slist_prepend (widget_segment->body.child.widgets,
child); child);
g_object_ref (G_OBJECT (child));
} }
void void
_gtk_widget_segment_remove (GtkTextLineSegment *widget_segment, _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment,
GtkWidget *child) GtkWidget *child)
{ {
g_assert (widget_segment->type = &gtk_text_child_type); g_return_if_fail (widget_segment->type = &gtk_text_child_type);
g_return_if_fail (widget_segment->body.child.tree != NULL);
widget_segment->body.child.widgets = widget_segment->body.child.widgets =
g_slist_remove (widget_segment->body.child.widgets, g_slist_remove (widget_segment->body.child.widgets,
@ -224,7 +255,7 @@ _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment)
{ {
g_assert (widget_segment->type = &gtk_text_child_type); g_assert (widget_segment->type = &gtk_text_child_type);
widget_segment->body.child.ref_count += 1; g_object_ref (G_OBJECT (widget_segment->body.child.obj));
} }
void void
@ -232,55 +263,112 @@ _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment)
{ {
g_assert (widget_segment->type = &gtk_text_child_type); g_assert (widget_segment->type = &gtk_text_child_type);
widget_segment->body.child.ref_count -= 1; g_object_unref (G_OBJECT (widget_segment->body.child.obj));
}
if (widget_segment->body.child.ref_count == 0) GtkTextLayout*
_gtk_anchored_child_get_layout (GtkWidget *child)
{
return gtk_object_get_data (GTK_OBJECT (child), "gtk-text-child-anchor-layout");
}
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);
static gpointer parent_class = NULL;
GType
gtk_text_child_anchor_get_type (void)
{
static GType object_type = 0;
if (!object_type)
{ {
GSList *tmp_list; 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,
};
if (widget_segment->body.child.tree == NULL) object_type = g_type_register_static (G_TYPE_OBJECT,
g_warning ("widget segment destroyed while still in btree"); "GtkTextChildAnchor",
&object_info, 0);
tmp_list = widget_segment->body.child.widgets;
while (tmp_list)
{
g_object_unref (G_OBJECT (tmp_list->data));
tmp_list = g_slist_next (tmp_list);
}
g_slist_free (widget_segment->body.child.widgets);
g_free (widget_segment);
} }
return object_type;
} }
void static void
gtk_text_child_anchor_ref (GtkTextChildAnchor *anchor) gtk_text_child_anchor_init (GtkTextChildAnchor *child_anchor)
{ {
GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; child_anchor->segment = NULL;
g_return_if_fail (seg->type = &gtk_text_child_type);
g_return_if_fail (seg->body.child.ref_count > 0);
_gtk_widget_segment_ref (seg);
} }
void static void
gtk_text_child_anchor_unref (GtkTextChildAnchor *anchor) gtk_text_child_anchor_class_init (GtkTextChildAnchorClass *klass)
{ {
GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_return_if_fail (seg->type = &gtk_text_child_type); parent_class = g_type_class_peek_parent (klass);
g_return_if_fail (seg->body.child.ref_count > 0);
_gtk_widget_segment_unref (seg); object_class->finalize = gtk_text_child_anchor_finalize;
}
static void
gtk_text_child_anchor_finalize (GObject *obj)
{
GtkTextChildAnchor *anchor;
GSList *tmp_list;
GtkTextLineSegment *seg;
anchor = GTK_TEXT_CHILD_ANCHOR (obj);
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);
anchor->segment = NULL;
} }
GList* GList*
gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor) gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor)
{ {
GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; GtkTextLineSegment *seg = anchor->segment;
GList *list = NULL; GList *list = NULL;
GSList *iter; GSList *iter;
@ -303,12 +391,63 @@ gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor)
gboolean gboolean
gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor) gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor)
{ {
GtkTextLineSegment *seg = (GtkTextLineSegment *) anchor; GtkTextLineSegment *seg = anchor->segment;
g_return_val_if_fail (seg->type = &gtk_text_child_type, TRUE); g_return_val_if_fail (seg->type = &gtk_text_child_type, TRUE);
return seg->body.child.tree == NULL; 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);
}

View File

@ -27,7 +27,7 @@
#ifndef GTK_TEXT_CHILD_H #ifndef GTK_TEXT_CHILD_H
#define GTK_TEXT_CHILD_H #define GTK_TEXT_CHILD_H
#include <glib.h> #include <glib-object.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -39,10 +39,31 @@ extern "C" {
* views. * 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); GList* gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor);
gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor); gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor);

View File

@ -69,19 +69,21 @@ typedef struct _GtkTextChildBody GtkTextChildBody;
struct _GtkTextChildBody struct _GtkTextChildBody
{ {
guint ref_count; GtkTextChildAnchor *obj;
GSList *widgets; GSList *widgets;
GtkTextBTree *tree; GtkTextBTree *tree;
GtkTextLine *line; GtkTextLine *line;
}; };
GtkTextLineSegment *_gtk_widget_segment_new (void); GtkTextLineSegment *_gtk_widget_segment_new (void);
void _gtk_widget_segment_add (GtkTextLineSegment *widget_segment, void _gtk_widget_segment_add (GtkTextLineSegment *widget_segment,
GtkWidget *child); GtkWidget *child);
void _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment, void _gtk_widget_segment_remove (GtkTextLineSegment *widget_segment,
GtkWidget *child); GtkWidget *child);
void _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment); void _gtk_widget_segment_ref (GtkTextLineSegment *widget_segment);
void _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment); void _gtk_widget_segment_unref (GtkTextLineSegment *widget_segment);
GtkTextLayout* _gtk_anchored_child_get_layout (GtkWidget *child);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -185,7 +185,7 @@ static void
render_layout_line (GdkDrawable *drawable, render_layout_line (GdkDrawable *drawable,
GtkTextRenderState *render_state, GtkTextRenderState *render_state,
PangoLayoutLine *line, PangoLayoutLine *line,
GSList **pixbuf_pointer, GSList **shaped_pointer,
int x, int x,
int y, int y,
gboolean selected) gboolean selected)
@ -272,68 +272,99 @@ render_layout_line (GdkDrawable *drawable,
x_off += logical_rect.width; x_off += logical_rect.width;
} }
else /* Pixbuf segment */ else /* Pixbuf or widget segment */
{ {
GtkTextPixbuf *pixbuf = (*pixbuf_pointer)->data; GObject *shaped = (*shaped_pointer)->data;
gint width, height;
GdkRectangle pixbuf_rect, draw_rect;
GdkBitmap *mask = NULL;
*pixbuf_pointer = (*pixbuf_pointer)->next; *shaped_pointer = (*shaped_pointer)->next;
width = gdk_pixbuf_get_width (pixbuf->pixbuf); if (GDK_IS_PIXBUF (shaped))
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))
{ {
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, GdkBitmap *mask = NULL;
gdk_pixbuf_get_width (pixbuf->pixbuf),
gdk_pixbuf_get_height (pixbuf->pixbuf),
1);
gdk_pixbuf_render_threshold_alpha (pixbuf->pixbuf, mask, if (gdk_pixbuf_get_has_alpha (pixbuf))
0, 0, 0, 0, {
gdk_pixbuf_get_width (pixbuf->pixbuf), mask = gdk_pixmap_new (drawable,
gdk_pixbuf_get_height (pixbuf->pixbuf), gdk_pixbuf_get_width (pixbuf),
128); 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;
{
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->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));
}
} }
else if (GTK_IS_WIDGET (shaped))
{
gint width, height;
GdkRectangle draw_rect;
GtkWidget *widget;
x_off += width * PANGO_SCALE; 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))
{
gtk_widget_draw (widget, &draw_rect);
}
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) int selection_end_index)
{ {
PangoRectangle logical_rect; PangoRectangle logical_rect;
GSList *pixbuf_pointer = line_display->pixbufs; GSList *shaped_pointer = line_display->shaped_objects;
GSList *tmp_list; GSList *tmp_list;
PangoAlignment align; PangoAlignment align;
PangoLayout *layout = line_display->layout; PangoLayout *layout = line_display->layout;
@ -431,15 +462,15 @@ render_para (GdkDrawable *drawable,
TRUE, TRUE,
x + line_display->left_margin, selection_y, x + line_display->left_margin, selection_y,
total_width / PANGO_SCALE, selection_height); 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, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
TRUE); TRUE);
} }
else 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, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
FALSE); FALSE);
@ -461,7 +492,7 @@ render_para (GdkDrawable *drawable,
logical_rect.width / PANGO_SCALE, logical_rect.width / PANGO_SCALE,
selection_height); 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, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
TRUE); TRUE);

View File

@ -849,21 +849,51 @@ gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
{ {
GtkTextRealIter *real; 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); real = gtk_text_iter_make_real (iter);
if (real == NULL) if (real == NULL)
return FALSE; return NULL;
check_invariants (iter); check_invariants (iter);
if (real->segment->type != &gtk_text_pixbuf_type) if (real->segment->type != &gtk_text_pixbuf_type)
return FALSE; return NULL;
else else
return real->segment->body.pixbuf.pixbuf; 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 != &gtk_text_child_type)
return NULL;
else
return real->segment->body.child.obj;
}
/** /**
* gtk_text_iter_get_marks: * gtk_text_iter_get_marks:
* @iter: an iterator * @iter: an iterator
@ -3733,6 +3763,25 @@ gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
check_invariants (iter); check_invariants (iter);
} }
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 void
gtk_text_btree_get_last_iter (GtkTextBTree *tree, gtk_text_btree_get_last_iter (GtkTextBTree *tree,
GtkTextIter *iter) GtkTextIter *iter)

View File

@ -28,6 +28,7 @@
#define GTK_TEXT_ITER_H #define GTK_TEXT_ITER_H
#include <gtk/gtktexttag.h> #include <gtk/gtktexttag.h>
#include <gtk/gtktextchild.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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); GdkPixbuf* gtk_text_iter_get_pixbuf (const GtkTextIter *iter);
GSList * gtk_text_iter_get_marks (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 /* Return list of tags toggled at this point (toggled_on determines
whether the list is of on-toggles or off-toggles) */ whether the list is of on-toggles or off-toggles) */
GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter, GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,

View File

@ -115,6 +115,7 @@ static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *ap
enum { enum {
INVALIDATED, INVALIDATED,
CHANGED, CHANGED,
ALLOCATE_CHILD,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -188,6 +189,18 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
GTK_TYPE_INT, GTK_TYPE_INT,
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); gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
object_class->destroy = gtk_text_layout_destroy; object_class->destroy = gtk_text_layout_destroy;
@ -1195,7 +1208,7 @@ add_text_attrs (GtkTextLayout *layout,
static void static void
add_pixbuf_attrs (GtkTextLayout *layout, add_pixbuf_attrs (GtkTextLayout *layout,
GtkTextLineDisplay *display, GtkTextLineDisplay *display,
GtkTextAttributes *style, GtkTextAttributes *style,
GtkTextLineSegment *seg, GtkTextLineSegment *seg,
PangoAttrList *attrs, PangoAttrList *attrs,
gint start) gint start)
@ -1218,7 +1231,70 @@ add_pixbuf_attrs (GtkTextLayout *layout,
attr->end_index = start + seg->byte_count; attr->end_index = start + seg->byte_count;
pango_attr_list_insert (attrs, attr); 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 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 * GtkTextLineDisplay *
gtk_text_layout_get_line_display (GtkTextLayout *layout, gtk_text_layout_get_line_display (GtkTextLayout *layout,
GtkTextLine *line, GtkTextLine *line,
@ -1329,7 +1418,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
{ {
/* Displayable segments */ /* Displayable segments */
if (seg->type == &gtk_text_char_type || if (seg->type == &gtk_text_char_type ||
seg->type == &gtk_text_pixbuf_type) seg->type == &gtk_text_pixbuf_type ||
seg->type == &gtk_text_child_type)
{ {
gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
&iter, line, &iter, line,
@ -1391,7 +1481,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
add_text_attrs (layout, style, byte_count, attrs, add_text_attrs (layout, style, byte_count, attrs,
byte_offset - byte_count, size_only); byte_offset - byte_count, size_only);
} }
else else if (seg->type == &gtk_text_pixbuf_type)
{ {
add_pixbuf_attrs (layout, display, style, add_pixbuf_attrs (layout, display, style,
seg, attrs, byte_offset); seg, attrs, byte_offset);
@ -1399,6 +1489,18 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
seg->byte_count); seg->byte_count);
byte_offset += seg->byte_count; byte_offset += seg->byte_count;
} }
else if (seg->type == &gtk_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); release_style (layout, style);
@ -1476,6 +1578,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
layout->one_display_cache = display; layout->one_display_cache = display;
allocate_child_widgets (layout, display);
return 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_foreach (display->cursors, (GFunc)g_free, NULL);
g_slist_free (display->cursors); g_slist_free (display->cursors);
g_slist_free (display->pixbufs); g_slist_free (display->shaped_objects);
} }
g_free (display); g_free (display);

View File

@ -185,7 +185,13 @@ struct _GtkTextLayoutClass
void (*free_line_data) (GtkTextLayout *layout, void (*free_line_data) (GtkTextLayout *layout,
GtkTextLine *line, GtkTextLine *line,
GtkTextLineData *line_data); GtkTextLineData *line_data);
void (*allocate_child) (GtkTextLayout *layout,
GtkWidget *child,
gint x,
gint y);
}; };
struct _GtkTextAttrAppearance struct _GtkTextAttrAppearance
{ {
PangoAttribute attr; PangoAttribute attr;
@ -203,7 +209,7 @@ struct _GtkTextLineDisplay
{ {
PangoLayout *layout; PangoLayout *layout;
GSList *cursors; GSList *cursors;
GSList *pixbufs; GSList *shaped_objects;
GtkTextDirection direction; GtkTextDirection direction;
@ -334,10 +340,23 @@ void gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
GtkTextIter *iter, GtkTextIter *iter,
gint count); gint count);
/* 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); void gtk_text_layout_spew (GtkTextLayout *layout);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -35,7 +35,6 @@
#include "gtktextview.h" #include "gtktextview.h"
#include "gtkimmulticontext.h" #include "gtkimmulticontext.h"
#include "gdk/gdkkeysyms.h" #include "gdk/gdkkeysyms.h"
#include "gtktexttypes.h"
#include <string.h> #include <string.h>
#define FOCUS_EDGE_WIDTH 1 #define FOCUS_EDGE_WIDTH 1
@ -235,7 +234,8 @@ struct _GtkTextViewChild
}; };
static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child, static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child,
GtkTextChildAnchor *anchor); GtkTextChildAnchor *anchor,
GtkTextLayout *layout);
static GtkTextViewChild* text_view_child_new_window (GtkWidget *child, static GtkTextViewChild* text_view_child_new_window (GtkWidget *child,
GtkTextWindowType type, GtkTextWindowType type,
gint x, gint x,
@ -244,7 +244,6 @@ static void text_view_child_free (GtkTextViewChild *child
static void text_view_child_realize (GtkTextView *text_view, static void text_view_child_realize (GtkTextView *text_view,
GtkTextViewChild *child); GtkTextViewChild *child);
static void text_view_child_unrealize (GtkTextViewChild *child);
struct _GtkTextWindow struct _GtkTextWindow
{ {
@ -278,7 +277,8 @@ static void text_window_get_allocation (GtkTextWindow *win,
GdkRectangle *rect); GdkRectangle *rect);
enum { enum
{
TARGET_STRING, TARGET_STRING,
TARGET_TEXT, TARGET_TEXT,
TARGET_COMPOUND_TEXT, TARGET_COMPOUND_TEXT,
@ -708,7 +708,7 @@ gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
} }
void void
gtk_text_view_set_buffer (GtkTextView *text_view, gtk_text_view_set_buffer (GtkTextView *text_view,
GtkTextBuffer *buffer) GtkTextBuffer *buffer)
{ {
g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); 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) 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_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer),
gtk_text_view_mark_set_handler, text_view); gtk_text_view_mark_set_handler, text_view);
gtk_object_unref (GTK_OBJECT (text_view->buffer)); gtk_object_unref (GTK_OBJECT (text_view->buffer));
@ -1251,6 +1272,7 @@ gtk_text_view_size_request (GtkWidget *widget,
GtkRequisition *requisition) GtkRequisition *requisition)
{ {
GtkTextView *text_view; GtkTextView *text_view;
GSList *tmp_list;
text_view = GTK_TEXT_VIEW (widget); text_view = GTK_TEXT_VIEW (widget);
@ -1268,6 +1290,69 @@ gtk_text_view_size_request (GtkWidget *widget,
if (text_view->bottom_window) if (text_view->bottom_window)
requisition->height += text_view->bottom_window->requisition.height; 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 static void
@ -1285,6 +1370,7 @@ gtk_text_view_size_allocate (GtkWidget *widget,
GdkRectangle right_rect; GdkRectangle right_rect;
GdkRectangle top_rect; GdkRectangle top_rect;
GdkRectangle bottom_rect; GdkRectangle bottom_rect;
GSList *tmp_list;
text_view = GTK_TEXT_VIEW (widget); text_view = GTK_TEXT_VIEW (widget);
@ -1383,6 +1469,8 @@ gtk_text_view_size_allocate (GtkWidget *widget,
gtk_text_layout_set_screen_width (text_view->layout, gtk_text_layout_set_screen_width (text_view->layout,
SCREEN_WIDTH (text_view)); SCREEN_WIDTH (text_view));
gtk_text_view_allocate_children (text_view);
gtk_text_view_validate_onscreen (text_view); gtk_text_view_validate_onscreen (text_view);
gtk_text_view_scroll_calc_now (text_view); gtk_text_view_scroll_calc_now (text_view);
@ -4187,7 +4275,8 @@ gtk_text_view_set_text_window_size (GtkTextView *text_view,
static GtkTextViewChild* static GtkTextViewChild*
text_view_child_new_anchored (GtkWidget *child, text_view_child_new_anchored (GtkWidget *child,
GtkTextChildAnchor *anchor) GtkTextChildAnchor *anchor,
GtkTextLayout *layout)
{ {
GtkTextViewChild *vc; GtkTextViewChild *vc;
@ -4197,12 +4286,14 @@ text_view_child_new_anchored (GtkWidget *child,
vc->anchor = anchor; vc->anchor = anchor;
g_object_ref (G_OBJECT (vc->widget)); 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_object_set_data (GTK_OBJECT (child),
"gtk-text-view-child", "gtk-text-view-child",
vc); vc);
gtk_text_child_anchor_register_child (anchor, child, layout);
return vc; return vc;
} }
@ -4235,8 +4326,14 @@ text_view_child_free (GtkTextViewChild *child)
gtk_object_remove_data (GTK_OBJECT (child->widget), gtk_object_remove_data (GTK_OBJECT (child->widget),
"gtk-text-view-child"); "gtk-text-view-child");
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_object_unref (G_OBJECT (child->widget));
gtk_text_child_anchor_unref (child->anchor);
g_free (child); g_free (child);
} }
@ -4259,12 +4356,6 @@ text_view_child_realize (GtkTextView *text_view,
gtk_widget_realize (vc->widget); gtk_widget_realize (vc->widget);
} }
static void
text_view_child_unrealize (GtkTextViewChild *vc)
{
gtk_widget_unrealize (vc->widget);
}
static void static void
add_child (GtkTextView *text_view, add_child (GtkTextView *text_view,
GtkTextViewChild *vc) 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_TEXT_VIEW (text_view));
g_return_if_fail (GTK_IS_WIDGET (child)); 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); 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); add_child (text_view, vc);
} }