Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / o_text.c
blob596b81b282d52de5323d89c2baf0da8e9a5bad52
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <math.h>
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
32 #include "gschem.h"
34 #ifdef HAVE_LIBDMALLOC
35 #include <dmalloc.h>
36 #endif
38 #define MINIMUM_MARK_SMALL_DIST 1
40 #if 1
41 # define FONT_NAME "Arial"
42 #else
43 # define FONT_NAME "Helvetica"
44 #endif
46 #undef DEBUG_TEXT
49 char *unescape_text_and_overbars (char *text, PangoAttrList *attrs)
51 char *p, *sp, *strip_text;
52 char *overbar_start = NULL;
53 int escape = FALSE;
55 /* The unescaped text is alwasys shorter than the original
56 string, so just allocate the same ammount of memory. */
57 sp = strip_text = g_malloc (strlen (text) + 1);
59 for (p = text; p != NULL; p++) {
60 int finish_overbar = FALSE;
62 /* If we find an escape character "\", we note it and continue looping */
63 if (!escape && *p == '\\') {
64 escape = TRUE;
65 continue;
68 if (escape && *p == '_') {
69 /* Overbar start or end sequence */
70 if (overbar_start != NULL) {
71 finish_overbar = TRUE;
72 } else {
73 overbar_start = sp;
75 } else {
76 /* just append the character, which may have been escaped */
77 *sp++ = *p;
79 escape = FALSE;
81 if (overbar_start != NULL &&
82 (finish_overbar || *p == '\0')) {
83 PangoAttribute *attr;
85 attr = gschem_pango_attr_overbar_new (TRUE);
86 attr->start_index = overbar_start - strip_text;
87 attr->end_index = sp - strip_text;
88 pango_attr_list_insert (attrs, attr);
89 overbar_start = NULL;
92 /* end of the string, stop iterating */
93 if (*p == '\0')
94 break;
97 return strip_text;
101 static void calculate_position (OBJECT *object,
102 PangoFontMetrics *font_metrics,
103 PangoRectangle logical_rect,
104 PangoRectangle inked_rect,
105 double *x, double *y)
107 double temp;
108 double y_lower, y_middle, y_upper;
109 double x_left, x_middle, x_right;
110 double descent = pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE;
112 x_left = 0;
113 x_middle = -logical_rect.width / 2.;
114 x_right = -logical_rect.width;
116 /*! \note Ideally, we would be using just font / logical metrics for vertical
117 * alignment, however this way seems to be more backward compatible
118 * with the old gschem rendering.
120 * Lower alignment is at the baseline of the bottom text line, whereas
121 * middle and upper alignment is based upon the inked extents of the
122 * entire text block.
124 y_upper = -inked_rect.y; /* Top of inked extents */
125 y_middle = y_upper - inked_rect.height / 2.; /* Middle of inked extents */
126 y_lower = descent - logical_rect.height; /* Baseline of bottom line */
128 /* Special case flips attachment point to opposite corner when
129 * the text is rotated to 180 degrees, since the drawing code
130 * does not rotate the text to be shown upside down.
132 if (object->text->angle == 180) {
133 temp = y_lower; y_lower = y_upper; y_upper = temp;
134 temp = x_left; x_left = x_right; x_right = temp;
137 switch (object->text->alignment) {
138 default:
139 /* Fall through to LOWER_left case */
140 case LOWER_LEFT: *y = y_lower; *x = x_left; break;
141 case MIDDLE_LEFT: *y = y_middle; *x = x_left; break;
142 case UPPER_LEFT: *y = y_upper; *x = x_left; break;
143 case LOWER_MIDDLE: *y = y_lower; *x = x_middle; break;
144 case MIDDLE_MIDDLE: *y = y_middle; *x = x_middle; break;
145 case UPPER_MIDDLE: *y = y_upper; *x = x_middle; break;
146 case LOWER_RIGHT: *y = y_lower; *x = x_right; break;
147 case MIDDLE_RIGHT: *y = y_middle; *x = x_right; break;
148 case UPPER_RIGHT: *y = y_upper; *x = x_right; break;
153 static PangoFontMetrics *setup_pango_return_metrics (GSCHEM_TOPLEVEL *w_current, PangoLayout *layout,
154 double scale_factor, OBJECT *o_current)
156 PangoContext *context;
157 PangoFontDescription *desc;
158 PangoFontMetrics *font_metrics;
159 PangoAttrList *attrs;
160 cairo_font_options_t *options;
161 double font_size_pt;
162 char *unescaped;
164 context = pango_layout_get_context (layout);
166 /* Switch off metric hinting, set medium outline hinting */
167 options = cairo_font_options_create ();
168 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
169 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_MEDIUM);
170 pango_cairo_context_set_font_options (context, options);
171 cairo_font_options_destroy (options);
173 pango_cairo_context_set_resolution (context, 1000. * scale_factor);
174 font_size_pt = o_text_get_font_size_in_points (w_current->toplevel,
175 o_current);
177 desc = pango_font_description_from_string (FONT_NAME);
178 pango_font_description_set_size (desc, (double)PANGO_SCALE * font_size_pt);
180 pango_layout_set_font_description (layout, desc);
181 font_metrics = pango_context_get_metrics (context, desc, NULL);
182 pango_font_description_free (desc);
184 attrs = pango_attr_list_new ();
185 unescaped = unescape_text_and_overbars (o_current->text->disp_string, attrs);
186 pango_layout_set_text (layout, unescaped, -1);
187 g_free (unescaped);
188 pango_layout_set_attributes (layout, attrs);
189 pango_attr_list_unref (attrs);
191 return font_metrics;
195 static void rotate_vector (double x, double y, double angle,
196 double *rx, double *ry)
198 double costheta = cos (angle * M_PI / 180.);
199 double sintheta = sin (angle * M_PI / 180.);
201 *rx = costheta * x - sintheta * y;
202 *ry = sintheta * x + costheta * y;
206 static void expand_bounds (int *left, int *top, int *right, int *bottom,
207 int new_x, int new_y)
209 *left = MIN (*left, new_x);
210 *right = MAX (*right, new_x);
211 *top = MIN (*top, new_y);
212 *bottom = MAX (*bottom, new_y);
216 /*! \todo Finish function documentation!!!
217 * \brief
218 * \par Function Description
221 int o_text_get_rendered_bounds (void *user_data, OBJECT *o_current,
222 int *min_x, int *min_y,
223 int *max_x, int *max_y)
225 GSCHEM_TOPLEVEL *w_current = user_data;
226 TOPLEVEL *toplevel = w_current->toplevel;
227 PangoLayout *layout;
228 cairo_t *cr;
229 double x, y;
230 PangoFontMetrics *font_metrics;
231 PangoRectangle logical_rect;
232 PangoRectangle inked_rect;
233 int angle;
234 double rx, ry;
235 double tleft, ttop, tright, tbottom;
236 int left, right, top, bottom;
238 g_return_val_if_fail (o_current != NULL, FALSE);
239 g_return_val_if_fail (o_current->text != NULL, FALSE);
241 if (o_current->visibility == INVISIBLE &&
242 !toplevel->show_hidden_text)
243 return FALSE;
245 if (o_current->text->disp_string == NULL)
246 return FALSE;
248 cr = gdk_cairo_create (w_current->drawable);
249 layout = pango_cairo_create_layout (cr);
251 font_metrics = setup_pango_return_metrics (w_current, layout, 1., o_current);
253 pango_layout_get_pixel_extents (layout, &inked_rect, &logical_rect);
254 calculate_position (o_current, font_metrics, logical_rect, inked_rect, &x, &y);
255 pango_font_metrics_unref (font_metrics);
257 tleft = x + inked_rect.x;
258 tright = x + inked_rect.x + inked_rect.width;
259 /* Deliberately include bounds up to the height of the logical rect,
260 * since we draw overbars in that space. In the unlikely event that
261 * the inked rect extends above the logical (inked_rect.y is -ve),
262 * do take that into account.
264 ttop = -y - (inked_rect.y < 0 ? inked_rect.y : 0.);
265 tbottom = -y - inked_rect.y - inked_rect.height;
267 angle = o_current->text->angle;
268 /* Special case turns upside down text back upright */
269 if (angle == 180)
270 angle = 0;
272 rotate_vector (tleft, ttop, angle, &rx, &ry);
273 left = right = rx;
274 top = bottom = ry;
275 rotate_vector (tright, ttop, angle, &rx, &ry);
276 expand_bounds (&left, &top, &right, &bottom, rx, ry);
277 rotate_vector (tleft, tbottom, angle, &rx, &ry);
278 expand_bounds (&left, &top, &right, &bottom, rx, ry);
279 rotate_vector (tright, tbottom, angle, &rx, &ry);
280 expand_bounds (&left, &top, &right, &bottom, rx, ry);
282 *min_x = o_current->text->x + left;
283 *max_x = o_current->text->x + right;
284 *min_y = o_current->text->y + top;
285 *max_y = o_current->text->y + bottom;
287 g_object_unref (layout);
288 cairo_destroy (cr);
290 return TRUE;
294 #ifdef DEBUG_TEXT
295 static void draw_construction_lines (GSCHEM_TOPLEVEL *w_current,
296 double x, double y,
297 PangoFontMetrics *font_metrics,
298 PangoRectangle logical_rect)
300 double px = 1.;
301 double dashlength;
302 double ascent = pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE;
303 double descent = pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE;
304 cairo_t *cr = w_current->cr;
306 /* Pick an arbitrary size constant for the construction lines */
307 /* Includes * 10 factor for precision */
308 px = SCREENabs (w_current, 4 * 10);
310 /* Threshold the drawing to be above a certain size */
311 if (px < 2.)
312 return;
314 px = px / 10.;
316 /* baseline, descent, ascent, height */
317 cairo_set_line_width (cr, 2 * px);
318 dashlength = 9 * px;
319 cairo_set_dash (cr, &dashlength, 1, 0);
321 /* Underline logical text rect in green, y coord is as gschem text origin */
322 cairo_set_source_rgba (cr, 0, 0.6, 0, 0.5);
323 cairo_move_to (cr, x + logical_rect.x, y + ascent);
324 cairo_rel_line_to (cr, logical_rect.width, 0);
325 cairo_stroke (cr);
327 /* Underline descent height in red */
328 cairo_set_source_rgba (cr, 1, 0, 0, 1);
329 cairo_move_to (cr, x + logical_rect.x, y + ascent + descent);
330 cairo_rel_line_to (cr, logical_rect.width, 0);
331 cairo_stroke (cr);
333 /* Overbar ascent height in yellow */
334 cairo_set_source_rgba (cr, 1, 1, 0, 1);
335 cairo_move_to (cr, x + logical_rect.x, y);
336 cairo_rel_line_to (cr, logical_rect.width, 0);
337 cairo_stroke (cr);
339 /* extents: width & height in blue */
340 cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
341 cairo_set_line_width (cr, px);
342 dashlength = 3 * px;
343 cairo_set_dash (cr, &dashlength, 1, 0);
344 cairo_rectangle (cr, x + logical_rect.x, y + logical_rect.y,
345 logical_rect.width, logical_rect.height);
346 cairo_stroke (cr);
348 /* show layout origin point in black */
349 cairo_arc (cr, x, y, 3 * px, 0, 2 * M_PI);
350 cairo_set_source_rgba (cr, 0.0, 0, 0, 0.5);
351 cairo_fill (cr);
353 /* text's advance in blue */
354 cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
355 cairo_arc (cr, x + logical_rect.x + logical_rect.width, y + logical_rect.height - descent,
356 3 * px, 0, 2 * M_PI);
357 cairo_fill (cr);
359 /* reference point in red */
360 cairo_arc (cr, x, y + ascent, 3 * px, 0, 2 * M_PI);
361 cairo_set_source_rgba (cr, 0.75, 0, 0, 0.5);
362 cairo_fill (cr);
364 #endif
367 /*! \todo Finish function documentation!!!
368 * \brief
369 * \par Function Description
372 static void o_text_draw_lowlevel(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
373 int dx, int dy, COLOR *color)
375 TOPLEVEL *toplevel = w_current->toplevel;
376 cairo_t *cr = w_current->cr;
377 int sx, sy;
378 double x, y;
379 PangoFontMetrics *font_metrics;
380 PangoRectangle logical_rect;
381 PangoRectangle inked_rect;
383 g_return_if_fail (o_current != NULL);
384 g_return_if_fail (o_current->text != NULL);
386 if (o_current->visibility == INVISIBLE &&
387 !toplevel->show_hidden_text)
388 return;
390 if (o_current->text->disp_string == NULL)
391 return;
393 font_metrics =
394 setup_pango_return_metrics (w_current, w_current->pl,
395 toplevel->page_current->to_screen_x_constant,
396 o_current);
398 pango_layout_get_pixel_extents (w_current->pl, &inked_rect, &logical_rect);
399 calculate_position (o_current, font_metrics, logical_rect, inked_rect, &x, &y);
401 cairo_save (cr);
403 WORLDtoSCREEN (w_current, o_current->text->x + dx,
404 o_current->text->y + dy, &sx, &sy);
405 cairo_translate (cr, sx, sy);
407 /* Special case turns upside-down text back upright */
408 if (o_current->text->angle != 180) {
409 cairo_rotate (cr, - M_PI * o_current->text->angle / 180.);
412 gschem_cairo_set_source_color (w_current, color);
414 /* NB: Shift the position by 0.5px to match the hinting applied to single
415 * pixel wide lines. This means the text will sit correctly on top of
416 * the grid lines, and ensures consistency with other lines when the
417 * page view is zoomed out. */
418 cairo_move_to (cr, x + 0.5, y + 0.5);
419 gschem_pango_show_layout (cr, w_current->pl);
421 #ifdef DEBUG_TEXT
422 draw_construction_lines (w_current, x, y, font_metrics, logical_rect);
423 #endif
425 pango_font_metrics_unref (font_metrics);
426 cairo_restore (cr);
430 /*! \todo Finish function documentation!!!
431 * \brief
432 * \par Function Description
435 void o_text_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
437 TOPLEVEL *toplevel = w_current->toplevel;
438 int screen_x1, screen_y1;
439 int small_dist, offset;
441 g_return_if_fail (o_current != NULL);
442 g_return_if_fail (o_current->type == OBJ_TEXT);
443 g_return_if_fail (o_current->text != NULL);
445 if (toplevel->DONT_REDRAW == 1 ||
446 (o_current->visibility == INVISIBLE && !toplevel->show_hidden_text)) {
447 return;
450 if (!w_current->fast_mousepan || !w_current->doing_pan) {
452 o_text_draw_lowlevel (w_current, o_current, 0, 0,
453 o_drawing_color (w_current, o_current));
455 /* Indicate on the schematic that the text is invisible by */
456 /* drawing a little I on the screen at the origin */
457 if (o_current->visibility == INVISIBLE && toplevel->show_hidden_text) {
458 if (toplevel->override_color != -1 ) {
459 gdk_gc_set_foreground(w_current->gc,
460 x_get_color(toplevel->override_color));
461 } else {
463 gdk_gc_set_foreground (w_current->gc, x_get_color (LOCK_COLOR));
466 offset = SCREENabs (w_current, 10);
467 small_dist = SCREENabs (w_current, 20);
468 WORLDtoSCREEN (w_current, o_current->text->x, o_current->text->y, &screen_x1, &screen_y1);
469 screen_x1 += offset;
470 screen_y1 += offset;
471 if (toplevel->DONT_REDRAW == 0) {
472 /* Top part of the I */
473 gdk_draw_line (w_current->drawable, w_current->gc,
474 screen_x1,
475 screen_y1,
476 screen_x1+small_dist,
477 screen_y1);
478 /* Middle part of the I */
479 gdk_draw_line (w_current->drawable, w_current->gc,
480 screen_x1+small_dist/2,
481 screen_y1,
482 screen_x1+small_dist/2,
483 screen_y1+small_dist);
484 /* Bottom part of the I */
485 gdk_draw_line (w_current->drawable, w_current->gc,
486 screen_x1,
487 screen_y1+small_dist,
488 screen_x1+small_dist,
489 screen_y1+small_dist);
492 } else {
493 /* draw a box in it's place */
494 gschem_cairo_box (w_current, 0,
495 o_current->w_left, o_current->w_bottom,
496 o_current->w_right, o_current->w_top);
498 gschem_cairo_set_source_color (w_current,
499 o_drawing_color (w_current, o_current));
500 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
502 return;
505 /* return if text origin marker displaying is disabled */
506 if (w_current->text_origin_marker == FALSE) {
507 return;
510 small_dist = SCREENabs (w_current, 10);
512 /* Switch of mark drawing for non-selected text, and at small sizes */
513 if (!o_current->selected || small_dist < MINIMUM_MARK_SMALL_DIST)
514 return;
516 WORLDtoSCREEN (w_current, o_current->text->x, o_current->text->y, &screen_x1, &screen_y1);
518 /* this is not really a fix, but a lame patch */
519 /* not having this will cause a bad draw of things when coords */
520 /* get close to the 2^15 limit of X */
521 if (screen_x1+small_dist > 32767 || screen_y1+small_dist > 32767) {
522 return;
525 if (toplevel->override_color != -1 ) {
526 gdk_gc_set_foreground(w_current->gc,
527 x_get_color(toplevel->override_color));
528 } else {
530 gdk_gc_set_foreground (w_current->gc, x_get_color (LOCK_COLOR));
533 if (toplevel->DONT_REDRAW == 0) {
534 gdk_draw_line (w_current->drawable, w_current->gc,
535 screen_x1-small_dist,
536 screen_y1+small_dist,
537 screen_x1+small_dist,
538 screen_y1-small_dist);
540 gdk_draw_line (w_current->drawable, w_current->gc,
541 screen_x1+small_dist,
542 screen_y1+small_dist,
543 screen_x1-small_dist,
544 screen_y1-small_dist);
549 /*! \todo Finish function documentation!!!
550 * \brief
551 * \par Function Description
554 void o_text_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
556 TOPLEVEL *toplevel = w_current->toplevel;
557 int factor;
559 if (o_current->visibility == INVISIBLE && !toplevel->show_hidden_text) {
560 return;
563 /* always display text which is 12 or larger */
564 factor = (int) toplevel->page_current->to_world_x_constant;
565 if ((factor < w_current->text_display_zoomfactor) ||
566 o_current->text->size >= 12 ||
567 w_current->text_feedback == ALWAYS) {
569 o_text_draw_lowlevel (w_current, o_current, dx, dy,
570 x_color_lookup_dark (o_current->color));
572 } else {
573 /* text is too small so draw a box in it's place */
575 gschem_cairo_box (w_current, 0,
576 o_current->w_left + dx, o_current->w_bottom + dy,
577 o_current->w_right + dx, o_current->w_top + dy);
579 gschem_cairo_set_source_color (w_current,
580 x_color_lookup_dark (o_current->color));
581 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
586 /*! \todo Finish function documentation!!!
587 * \brief
588 * \par Function Description
591 void o_text_prepare_place(GSCHEM_TOPLEVEL *w_current, char *text)
593 TOPLEVEL *toplevel = w_current->toplevel;
595 /* Insert the new object into the buffer at world coordinates (0,0).
596 * It will be translated to the mouse coordinates during placement. */
598 w_current->first_wx = 0;
599 w_current->first_wy = 0;
601 w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
603 /* remove the old place list if it exists */
604 s_delete_object_glist(toplevel, toplevel->page_current->place_list);
605 toplevel->page_current->place_list = NULL;
607 /* here you need to add OBJ_TEXT when it's done */
608 toplevel->page_current->place_list =
609 g_list_append(toplevel->page_current->place_list,
610 o_text_new (toplevel, OBJ_TEXT, TEXT_COLOR,
611 0, 0, LOWER_LEFT, 0, /* zero is angle */
612 text,
613 w_current->text_size,
614 /* has to be visible so you can place it */
615 /* visibility is set when you create the object */
616 VISIBLE, SHOW_NAME_VALUE));
618 w_current->inside_action = 1;
619 i_set_state (w_current, ENDTEXT);
623 /*! \todo Finish function documentation!!!
624 * \brief
625 * \par Function Description
628 void o_text_edit(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
630 /* you need to check to make sure only one object is selected */
631 /* no actually this is okay... not here in o_edit */
632 text_edit_dialog(w_current,
633 o_text_get_string (w_current->toplevel, o_current),
634 o_current->text->size, o_current->text->alignment);
637 /*! \todo Finish function documentation!!!
638 * \brief
639 * \par Function Description
642 void o_text_edit_end(GSCHEM_TOPLEVEL *w_current, char *string, int len, int text_size,
643 int text_alignment)
645 TOPLEVEL *toplevel = w_current->toplevel;
646 OBJECT *object;
647 GList *s_current;
648 int numselect;
650 /* skip over head */
651 s_current = geda_list_get_glist( toplevel->page_current->selection_list );
652 numselect = g_list_length( geda_list_get_glist( toplevel->page_current->selection_list ));
654 while(s_current != NULL) {
655 object = (OBJECT *) s_current->data;
657 if (object) {
658 if (object->type == OBJ_TEXT) {
659 o_invalidate (w_current, object);
661 object->text->size = text_size;
662 object->text->alignment = text_alignment;
664 /* probably the text object should be extended to carry a color */
665 /* and we should pass it here with a function parameter (?) */
666 object->color = w_current->edit_color;
668 /* only change text string if there is only ONE text object selected */
669 if (numselect == 1 && string) {
670 o_text_set_string (w_current->toplevel, object, string);
671 /* handle slot= attribute, it's a special case */
672 if (object->attached_to != NULL &&
673 g_ascii_strncasecmp (string, "slot=", 5) == 0) {
674 o_slot_end (w_current, object->attached_to, string);
677 o_text_recreate(toplevel, object);
678 o_invalidate (w_current, object);
682 s_current = g_list_next(s_current);
685 toplevel->page_current->CHANGED = 1;
686 o_undo_savestate(w_current, UNDO_ALL);
689 /*! \todo Finish function documentation!!!
690 * \brief
691 * \par Function Description
693 * \note
694 * The object passed in should be the REAL object, NOT any copy in any
695 * selection list
697 void o_text_change(GSCHEM_TOPLEVEL *w_current, OBJECT *object, char *string,
698 int visibility, int show)
700 TOPLEVEL *toplevel = w_current->toplevel;
701 if (object == NULL) {
702 return;
705 if (object->type != OBJ_TEXT) {
706 return;
709 /* erase old object */
710 o_invalidate (w_current, object);
712 /* second change the real object */
713 o_text_set_string (toplevel, object, string);
715 object->visibility = visibility;
716 object->show_name_value = show;
717 o_text_recreate(toplevel, object);
718 o_invalidate (w_current, object);
720 /* handle slot= attribute, it's a special case */
721 if (object->attached_to != NULL &&
722 g_ascii_strncasecmp (string, "slot=", 5) == 0) {
723 o_slot_end (w_current, object->attached_to, string);
726 toplevel->page_current->CHANGED = 1;