From 8ad2ab73dece42dbca8b9039cbda139143442c85 Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Fri, 5 Aug 2005 10:08:05 +0000 Subject: [PATCH] doing more work on tb SVN revision: 16037 --- legacy/evas/src/lib/Evas.h | 7 +- .../src/lib/canvas/evas_object_textblock.c | 729 +++++++++++++++++- 2 files changed, 704 insertions(+), 32 deletions(-) diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index aa96d0c906..1315336ec5 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -475,7 +475,7 @@ extern "C" { EAPI const Evas_Textblock_Style *evas_object_textblock2_style_get(Evas_Object *obj); EAPI void evas_object_textblock2_text_markup_set(Evas_Object *obj, const char *text); - EAPI char *evas_object_textblock2_text_markup_get(Evas_Object *obj); + EAPI const char *evas_object_textblock2_text_markup_get(Evas_Object *obj); EAPI const Evas_Textblock_Cursor *evas_object_textblock2_cursor_get(Evas_Object *obj); EAPI Evas_Textblock_Cursor *evas_object_textblock2_cursor_new(Evas_Object *obj); @@ -490,9 +490,8 @@ extern "C" { EAPI void evas_textblock2_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text); EAPI const char *evas_textblock2_cursor_node_text_get(Evas_Textblock_Cursor *cur); - EAPI void evas_textblock2_cursor_format_push(Evas_Textblock_Cursor *cur, const char *format); - EAPI void evas_textblock2_cursor_format_pop(Evas_Textblock_Cursor *cur); - EAPI const char *evas_textblock2_cursor_format_get(Evas_Textblock_Cursor *cur); + EAPI void evas_textblock2_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format); + EAPI const char *evas_textblock2_cursor_node_format_get(Evas_Textblock_Cursor *cur); EAPI void evas_object_textblock2_clear(Evas_Object *obj); EAPI void evas_object_textblock2_size_requested_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h); diff --git a/legacy/evas/src/lib/canvas/evas_object_textblock.c b/legacy/evas/src/lib/canvas/evas_object_textblock.c index ae2121f53a..261527c9fa 100644 --- a/legacy/evas/src/lib/canvas/evas_object_textblock.c +++ b/legacy/evas/src/lib/canvas/evas_object_textblock.c @@ -20,8 +20,10 @@ static const char o_type[] = "textblock"; /* private struct for textblock object internal data */ -typedef struct _Evas_Object_Textblock Evas_Object_Textblock; -typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; +typedef struct _Evas_Object_Textblock Evas_Object_Textblock; +typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; +typedef struct _Evas_Object_Textblock_Node Evas_Object_Textblock_Node; +typedef struct _Evas_Object_Textblock_Lnode Evas_Object_Textblock_Lnode; /* the current state of the formatting */ @@ -33,31 +35,55 @@ struct _Evas_Object_Style_Tag char *replace; }; +#define NODE_TEXT 0 +#define NODE_FORMAT 1 + +struct _Evas_Object_Textblock_Node +{ + Evas_Object_List _list_data; + int type; + char *text; + int len, alloc; +}; + +struct _Evas_Object_Textblock_Lnode +{ + Evas_Object_List _list_data; + int type; + char *text; + int len, alloc; +}; + struct _Evas_Textblock_Style { - char *style_text; - char *default_tag; + char *style_text; + char *default_tag; Evas_Object_Style_Tag *tags; - Evas_List *objects; - unsigned char delete_me : 1; + Evas_List *objects; + unsigned char delete_me : 1; }; struct _Evas_Textblock_Cursor { - Evas_Object *obj; - int pos; + Evas_Object *obj; + int pos; + Evas_Object_Textblock_Node *node; }; struct _Evas_Object_Textblock { - DATA32 magic; + DATA32 magic; struct { - int dummy; + int dummy; } cur, prev; - char *markup_text; - Evas_Textblock_Style *style; - char changed : 1; - void *engine_data; + Evas_Textblock_Style *style; + Evas_Textblock_Cursor *cursor; + Evas_List *cursors; + Evas_Object_Textblock_Node *nodes; + Evas_Object_Textblock_Lnode *lnodes; + char *markup_text; + char changed : 1; + void *engine_data; }; /* private methods for textblock objects */ @@ -151,7 +177,7 @@ evas_object_textblock2_add(Evas *e) // popped // tags starting with / (ie ) will ALWAYS pop UNLESS provided // with an override here in the style (like /p) - "DEFAULT='font=Vera font_size=10 align=left color=#000000'" + "DEFAULT='push font=Vera font_size=10 align=left color=#000000'" "center='push align=middle'" "h1='push font_size=20'" "red='push color=#ff0000'" @@ -320,6 +346,7 @@ void evas_object_textblock2_style_set(Evas_Object *obj, Evas_Textblock_Style *ts) { TB_HEAD(); + if (ts == o->style) return; if ((ts) && (ts->delete_me)) return; if (o->style) { @@ -367,17 +394,495 @@ evas_object_textblock2_style_get(Evas_Object *obj) ); } #endif + +static char * +_style_match_replace(Evas_Textblock_Style *ts, char *s) +{ + Evas_Object_List *l; + + for (l = (Evas_Object_List *)ts->tags; l; l = l->next) + { + Evas_Object_Style_Tag *tag; + + tag = (Evas_Object_Style_Tag *)l; + if (!strcmp(tag->replace, s)) return tag->tag; + } + return NULL; +} + +static char * +_style_match_tag(Evas_Textblock_Style *ts, char *s) +{ + Evas_Object_List *l; + + for (l = (Evas_Object_List *)ts->tags; l; l = l->next) + { + Evas_Object_Style_Tag *tag; + + tag = (Evas_Object_Style_Tag *)l; + if (!strcmp(tag->tag, s)) return tag->replace; + } + return NULL; +} + +static char * +_strbuf_append(char *s, char *s2, int *len, int *alloc) +{ + int l2; + int tlen; + + if (!s2) return s; + l2 = strlen(s2); + tlen = *len + l2; + if (tlen > *alloc) + { + char *ts; + int talloc; + + talloc = ((tlen + 31) >> 5) << 5; + ts = realloc(s, talloc); + if (!ts) return s; + s = ts; + *alloc = talloc; + } + strcpy(s + *len, s2); + *len = tlen; + return s; +} + +static char * +_strbuf_append_n(char *s, char *s2, int n, int *len, int *alloc) +{ + int l2; + int tlen; + + if (!s2) return s; + l2 = 0; + if (n < 1) return s; + else + { + char *p; + for (p = s2; (l2 < n) && (*p != 0); p++, l2++); + } + tlen = *len + l2; + if (tlen > *alloc) + { + char *ts; + int talloc; + + talloc = ((tlen + 31) >> 5) << 5; + ts = realloc(s, talloc); + if (!ts) return s; + s = ts; + *alloc = talloc; + } + strncpy(s + *len, s2, l2); + *len = tlen; + s[tlen] = 0; + return s; +} + +static void +_nodes_clear(Evas_Object *obj) +{ + Evas_Object_Textblock *o; + + o = (Evas_Object_Textblock *)(obj->object_data); + while (o->nodes) + { + Evas_Object_Textblock_Node *n; + + n = (Evas_Object_Textblock_Node *)o->nodes; + o->nodes = evas_object_list_remove(o->nodes, n); + if (n->text) free(n->text); + free(n); + } +} + +static void +_lnodes_clear(Evas_Object *obj) +{ + Evas_Object_Textblock *o; + + o = (Evas_Object_Textblock *)(obj->object_data); + while (o->lnodes) + { + Evas_Object_Textblock_Lnode *ln; + + ln = (Evas_Object_Textblock_Lnode *)o->lnodes; + o->lnodes = evas_object_list_remove(o->lnodes, ln); + if (ln->text) free(ln->text); + free(ln); + } +} + +/* table of html escapes (that i can find) this shoudl be ordered with the + * most common first as it's a linear search to match - no hash for this + */ +static const char *_escapes[] = +{ +/* most common escaped stuff */ + "<", "<", + ">", ">", + "&", "&", + " ", " ", /* NOTE: we will allow nbsp's to break as we map early */ + """, "\"", + /* all the rest */ + "©", "©", + "®", "®", + "Ñ", "Ñ", + "ñ", "ñ", + "Ç", "Ç", + "ç", "ç", + "ß", "ß", + "Þ", "Þ", + "þ", "þ", + "Ð", "Ð", + "ð", "ð", + "´", "´", + "¸", "¸", + "°", "°", + "¨", "¨", + "¢", "¢", + "£", "£", + "¤", "¤", + "¥", "¥", + "§", "§", + "¶", "¶", + "«", "«", + "»", "»", + "¡", "¡", + "¿", "¿", + "¦", "¦", + "ª", "ª", + "º", "º", + "µ", "µ", + "¯", "¯", + "⊕", "⊕", + "∫", "∫", + "∑", "∑", + "∏", "∏", + "⊥", "⊥", + "∨", "∨", + "∧", "∧", + "≡", "≡", + "≠", "≠", + "∀", "∀", + "∃", "∃", + "∇", "∇", + "←", "←", + "→", "→", + "↑", "↑", + "↓", "↓", + "↔", "↔", + "⇐", "⇐", + "⇒", "⇒", + "±", "±", + "·", "·", + "×", "×", + "÷", "÷", + "¹", "¹", + "²", "²", + "³", "³", + "¼", "¼", + "½", "½", + "¾", "¾", + "¬", "¬", + "Á", "Á", + "É", "É", + "Í", "Í", + "Ó", "Ó", + "Ú", "Ú", + "Ý", "Ý", + "á", "á", + "é", "é", + "í", "í", + "ó", "ó", + "ú", "ú", + "ý", "ý", + "Â", "Â", + "Ê", "Ê", + "Î", "Î", + "Ô", "Ô", + "Û", "Û", + "â", "â", + "ê", "ê", + "î", "î", + "ô", "ô", + "û", "û", + "À", "À", + "È", "È", + "Ì", "Ì", + "Ò", "Ò", + "Ù", "Ù", + "à", "à", + "è", "è", + "ì", "ì", + "ò", "ò", + "ù", "ù", + "Ä", "Ä", + "Ë", "Ë", + "Ï", "Ï", + "Ö", "Ö", + "ä", "ä", + "ë", "ë", + "ï", "ï", + "ö", "ö", + "ü", "ü", + "ÿ", "ÿ", + "Ã", "Ã", + "ã", "ã", + "Õ", "Õ", + "õ", "õ", + "å", "å", + "Å", "Å", + "Ø", "Ø", + "ø", "ø", + "Æ", "Æ", + "æ", "æ", + "Ñ", "Ñ", + "ñ", "ñ", + "Ç", "Ç", + "ç", "ç", + "ß", "ß", + "Þ", "Þ", + "þ", "þ", + "Ð", "Ð", + "ð", "ð", + "α", "α", + "β", "β", + "γ", "γ", + "δ", "δ", + "ε", "ε", + "ζ", "ζ", + "η", "η", + "θ", "θ", + "ι", "ι", + "κ", "κ", + "μ", "μ", + "ν", "ν", + "ο", "ο", + "ξ", "ξ", + "π", "π", + "ρ", "ρ", + "σ", "σ", + "τ", "τ", + "υ", "υ", + "φ", "φ", + "χ", "χ", + "ψ", "ψ", + "ω", "ω" +}; + void evas_object_textblock2_text_markup_set(Evas_Object *obj, const char *text) { TB_HEAD(); + if (o->markup_text) + { + free(o->markup_text); + o->markup_text = NULL; + } + if (text) o->markup_text = strdup(text); + _nodes_clear(obj); + _lnodes_clear(obj); + o->changed = 1; + evas_object_change(obj); + if (o->markup_text) + { + char *s, *p; + char *tag_start, *tag_end, *esc_start, *esc_end; + + tag_start = tag_end = esc_start = esc_end = NULL; + p = o->markup_text; + s = p; + for (;;) + { + if ((*p == 0) || + (tag_end) || (esc_end) || + (tag_start) || (esc_start)) + { + if (tag_end) + { + char *ttag; + + ttag = malloc(tag_end - tag_start); + if (ttag) + { + strncpy(ttag, tag_start + 1, tag_end - tag_start - 1); + ttag[tag_end - tag_start] = 0; + s = _style_match_tag(o->style, ttag); + if (s) + evas_textblock2_cursor_format_append(o->cursor, s); + else + evas_textblock2_cursor_format_append(o->cursor, ttag); + free(ttag); + } + tag_start = tag_end = NULL; + } + else if (esc_end) + { + int i; + + for (i = 0; i < (sizeof(_escapes) / sizeof(char *)); i += 2) + { + if (!strncmp(_escapes[i], esc_start, + esc_end - esc_start + 1)) + { + evas_textblock2_cursor_text_append(o->cursor, _escapes[i + 1]); + break; + } + } + esc_start = esc_end = NULL; + } + else if (s) + { + char *ts; + + ts = malloc(p - s); + if (ts) + { + strncpy(ts, s, p - s - 1); + ts[p - s] = 0; + evas_textblock2_cursor_text_append(o->cursor, ts); + free(ts); + } + s = NULL; + } + if (*p == 0) + break; + } + if (*p == '<') + { + if (!esc_start) + { + tag_start = p; + tag_end = NULL; + } + } + else if (*p == '>') + { + if (tag_start) + { + tag_end = p; + s = p + 1; + } + } + else if (*p == '&') + { + if (!tag_start) + { + esc_start = p; + esc_end = NULL; + } + } + else if (*p == ';') + { + if (esc_start) + { + esc_end = p; + s = p + 1; + } + } + p++; + } + } } -char * +const char * evas_object_textblock2_text_markup_get(Evas_Object *obj) { TB_HEAD_RETURN(NULL); - return NULL; + if (!o->markup_text) + { + Evas_Textblock_Cursor *cur; + int slen = 0; + int salloc = 0; + + cur = evas_object_textblock2_cursor_new(obj); + evas_textblock2_cursor_node_first(cur); + do + { + char *s, *p, *ps; + + s = (char *)evas_textblock2_cursor_node_text_get(cur); + if (s) + { + p = s; + ps = p; + for (;;) + { + if (*p == 0) + { + o->markup_text = _strbuf_append(o->markup_text, + ps, + &slen, &salloc); + break; + } + else if (*p == '<') + { + o->markup_text = _strbuf_append_n(o->markup_text, + ps, p - ps, + &slen, &salloc); + o->markup_text = _strbuf_append(o->markup_text, + "<", + &slen, &salloc); + ps = p + 1; + } + else if (*p == '>') + { + o->markup_text = _strbuf_append_n(o->markup_text, + ps, p - ps, + &slen, &salloc); + o->markup_text = _strbuf_append(o->markup_text, + ">", + &slen, &salloc); + ps = p + 1; + } + else if (*p == '&') + { + o->markup_text = _strbuf_append_n(o->markup_text, + ps, p - ps, + &slen, &salloc); + o->markup_text = _strbuf_append(o->markup_text, + "&", + &slen, &salloc); + ps = p + 1; + } + /* FIXME: learn how to do all the other escapes */ + p++; + } + } + else + { + s = (char *)evas_textblock2_cursor_node_format_get(cur); + if (s) + { + char *stag; + + o->markup_text = _strbuf_append(o->markup_text, + "<", + &slen, &salloc); + stag = _style_match_replace(o->style, s); + if (stag) + o->markup_text = _strbuf_append(o->markup_text, + stag, + &slen, &salloc); + else + o->markup_text = _strbuf_append(o->markup_text, + s, + &slen, &salloc); + o->markup_text = _strbuf_append(o->markup_text, + ">", + &slen, &salloc); + } + } + + } + while (evas_textblock2_cursor_node_next(cur)); + evas_textblock2_cursor_free(cur); + } + return o->markup_text; } /* cursors */ @@ -385,40 +890,99 @@ const Evas_Textblock_Cursor * evas_object_textblock2_cursor_get(Evas_Object *obj) { TB_HEAD_RETURN(NULL); - return NULL; + return o->cursor; } Evas_Textblock_Cursor * evas_object_textblock2_cursor_new(Evas_Object *obj) { + Evas_Textblock_Cursor *cur; + TB_HEAD_RETURN(NULL); - return NULL; + cur = calloc(1, sizeof(Evas_Textblock_Cursor)); + cur->obj = obj; + cur->node = o->nodes; + cur->pos = 0; + o->cursors = evas_list_append(o->cursors, cur); + return cur; } void evas_textblock2_cursor_free(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock *o; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + if (cur == o->cursor) return; + o->cursors = evas_list_remove(o->cursors, cur); + free(cur); } void evas_textblock2_cursor_node_first(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock *o; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + cur->node = o->nodes; + cur->pos = 0; } void evas_textblock2_cursor_node_last(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock *o; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + if (o->nodes) + { + cur->node = (Evas_Object_Textblock_Node *)(((Evas_Object_List *)(o->nodes))->last); + if (cur->node->type == NODE_TEXT) + cur->pos = cur->node->len - 1; + else + cur->pos = 0; + } + else + { + cur->node = NULL; + cur->pos = 0; + } } Evas_Bool evas_textblock2_cursor_node_next(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock *o; + + if (!cur) return 0; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + if (!cur->node) return 0; + if (((Evas_Object_List *)(o->nodes))->next) + { + cur->node = (Evas_Object_Textblock_Node *)(((Evas_Object_List *)(o->nodes))->next); + cur->pos = 0; + return 1; + } return 0; } Evas_Bool evas_textblock2_cursor_node_prev(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock *o; + + if (!cur) return 0; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + if (!cur->node) return 0; + if (((Evas_Object_List *)(o->nodes))->prev) + { + cur->node = (Evas_Object_Textblock_Node *)(((Evas_Object_List *)(o->nodes))->prev); + cur->pos = 0; + return 1; + } return 0; } @@ -426,27 +990,67 @@ evas_textblock2_cursor_node_prev(Evas_Textblock_Cursor *cur) void evas_textblock2_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text) { + Evas_Object_Textblock *o; + Evas_Object_Textblock_Node *n; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + n = cur->node; + if ((!n) || (n->type == NODE_FORMAT)) + { + n = calloc(1, sizeof(Evas_Object_Textblock_Node)); + n->type = NODE_TEXT; + o->nodes = evas_object_list_append(o->nodes, n); + } + n->text = _strbuf_append(n->text, (char *)text, &(n->len), &(n->alloc)); + cur->node = n; + cur->pos = n->len - 1; + _lnodes_clear(cur->obj); + o->changed = 1; + evas_object_change(cur->obj); } const char * evas_textblock2_cursor_node_text_get(Evas_Textblock_Cursor *cur) { + if (!cur) return NULL; + if (!cur->node) return NULL; + if (cur->node->type == NODE_TEXT) + { + return cur->node->text; + } + return NULL; } /* formatting controls */ void -evas_textblock2_cursor_format_push(Evas_Textblock_Cursor *cur, const char *format) -{ -} - -void -evas_textblock2_cursor_format_pop(Evas_Textblock_Cursor *cur) +evas_textblock2_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) { + Evas_Object_Textblock *o; + Evas_Object_Textblock_Node *n; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + n = calloc(1, sizeof(Evas_Object_Textblock_Node)); + n->type = NODE_FORMAT; + o->nodes = evas_object_list_append(o->nodes, n); + n->text = _strbuf_append(n->text, (char *)format, &(n->len), &(n->alloc)); + cur->node = n; + cur->pos = 0; + _lnodes_clear(cur->obj); + o->changed = 1; + evas_object_change(cur->obj); } const char * -evas_textblock_cursor_format_get(Evas_Textblock_Cursor *cur) +evas_textblock2_cursor_node_format_get(Evas_Textblock_Cursor *cur) { + if (!cur) return NULL; + if (!cur->node) return NULL; + if (cur->node->type == NODE_FORMAT) + { + return cur->node->text; + } return NULL; } @@ -454,8 +1058,26 @@ evas_textblock_cursor_format_get(Evas_Textblock_Cursor *cur) void evas_object_textblock2_clear(Evas_Object *obj) { + Evas_List *l; + TB_HEAD(); - /* FIXME: clear */ + _nodes_clear(obj); + o->cursor->node = NULL; + o->cursor->pos = 0; + for (l = o->cursors; l; l = l->next) + { + Evas_Textblock_Cursor *cur; + + cur = (Evas_Textblock_Cursor *)l->data; + cur->node = NULL; + cur->pos = 0; + } + if (o->markup_text) + { + free(o->markup_text); + o->markup_text = NULL; + } + _lnodes_clear(obj); o->changed = 1; evas_object_change(obj); } @@ -464,9 +1086,35 @@ void evas_object_textblock2_size_requested_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) { TB_HEAD(); + /* FIXME */ } - +static void +_layout(Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret) +{ + Evas_Object_Textblock *o; + Evas_Object_List *l; + Evas_Object_Textblock_Lnode *lnodes = NULL; + int x, y, wmax, hmax; + + x = 0; + y = 0; + wmax = 0; + hmax = 0; + o = (Evas_Object_Textblock *)(obj->object_data); + /* FIXME: generate format stack using default format from the style */ + for (l = (Evas_Object_List *)o->nodes; l; l = l->next) + { + Evas_Object_Textblock_Node *n; + + n = (Evas_Object_Textblock_Node *)l; + /* FIXME: go thru o->nodes and generate o->lnodes */ + } + if (!calc_only) + { + o->lnodes = lnodes; + } +} @@ -474,6 +1122,8 @@ evas_object_textblock2_size_requested_get(Evas_Object *obj, Evas_Coord *w, Evas_ static void evas_object_textblock_init(Evas_Object *obj) { + Evas_Object_Textblock *o; + /* alloc image ob, setup methods and default values */ obj->object_data = evas_object_textblock_new(); /* set up default settings for this kind of object */ @@ -491,6 +1141,9 @@ evas_object_textblock_init(Evas_Object *obj) /* set up methods (compulsory) */ obj->func = &object_func; obj->type = o_type; + + o = (Evas_Object_Textblock *)(obj->object_data); + o->cursor->obj = obj; } static void * @@ -501,6 +1154,7 @@ evas_object_textblock_new(void) /* alloc obj private data */ o = calloc(1, sizeof(Evas_Object_Textblock)); o->magic = MAGIC_OBJ_TEXTBLOCK; + o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor)); return o; } @@ -509,7 +1163,18 @@ evas_object_textblock_free(Evas_Object *obj) { Evas_Object_Textblock *o; + evas_object_textblock2_clear(obj); + evas_object_textblock2_style_set(obj, NULL); o = (Evas_Object_Textblock *)(obj->object_data); + free(o->cursor); + while (o->cursors) + { + Evas_Textblock_Cursor *cur; + + cur = (Evas_Textblock_Cursor *)o->cursors->data; + o->cursors = evas_list_remove_list(o->cursors, o->cursors); + free(cur); + } o->magic = 0; free(o); } @@ -559,6 +1224,14 @@ evas_object_textblock_render_pre(Evas_Object *obj) /* then when this is done the object needs to figure if it changed and */ /* if so what and where and add the appropriate redraw textblocks */ o = (Evas_Object_Textblock *)(obj->object_data); + if (o->changed) + { + _layout(obj, + 0, + obj->cur.geometry.w, obj->cur.geometry.h, + NULL, NULL); + o->changed = 0; + } /* if someone is clipping this obj - go calculate the clipper */ if (obj->cur.clipper) {