diff --git a/ChangeLog b/ChangeLog index 40dacf7a2..aae7c1f93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2002-02-09 Havoc Pennington + + * src/theme.c (meta_draw_op_draw_with_env): implement wacky "tile" + draw op to lose some of the PNG files in Gorilla theme + + * src/theme-parser.c: parse the tile primitive + 2002-02-09 Havoc Pennington * src/window.c (update_icon): port to icon cache diff --git a/src/theme-parser.c b/src/theme-parser.c index d857be81d..45006157b 100644 --- a/src/theme-parser.c +++ b/src/theme-parser.c @@ -57,6 +57,7 @@ typedef enum STATE_ICON, STATE_TITLE, STATE_INCLUDE, /* include another draw op list */ + STATE_TILE, /* tile another draw op list */ /* sub-parts of gradient */ STATE_COLOR, /* frame style */ @@ -2637,7 +2638,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (name == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("No \"name\" attribute on element <%s>"), element_name); + _("No \"%s\" attribute on element <%s>"), "name", element_name); return; } @@ -2697,6 +2698,130 @@ parse_draw_op_element (GMarkupParseContext *context, push_state (info, STATE_INCLUDE); } + else if (ELEMENT_IS ("tile")) + { + MetaDrawOp *op; + const char *name; + const char *x; + const char *y; + const char *width; + const char *height; + const char *tile_xoffset; + const char *tile_yoffset; + const char *tile_width; + const char *tile_height; + MetaDrawOpList *op_list; + + if (!locate_attributes (context, element_name, attribute_names, attribute_values, + error, + "x", &x, "y", &y, + "width", &width, "height", &height, + "name", &name, + "tile_xoffset", &tile_xoffset, + "tile_yoffset", &tile_yoffset, + "tile_width", &tile_width, + "tile_height", &tile_height, + NULL)) + return; + + if (name == NULL) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("No \"%s\" attribute on element <%s>"), "name", element_name); + return; + } + + if (tile_width == NULL) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("No \"%s\" attribute on element <%s>"), "tile_width", element_name); + return; + } + + if (tile_height == NULL) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("No \"%s\" attribute on element <%s>"), "tile_height", element_name); + return; + } + + /* These default to 0 */ + if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error)) + return; + + if (tile_yoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error)) + return; + + /* x/y/width/height default to 0,0,width,height - should + * probably do this for all the draw ops + */ + + if (x && !check_expression (x, FALSE, info->theme, context, error)) + return; + + if (y && !check_expression (y, FALSE, info->theme, context, error)) + return; + + if (width && !check_expression (width, FALSE, info->theme, context, error)) + return; + + if (height && !check_expression (height, FALSE, info->theme, context, error)) + return; + + if (!check_expression (tile_width, FALSE, info->theme, context, error)) + return; + + if (!check_expression (tile_height, FALSE, info->theme, context, error)) + return; + + op_list = meta_theme_lookup_draw_op_list (info->theme, + name); + if (op_list == NULL) + { + set_error (error, context, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("No called \"%s\" has been defined"), + name); + return; + } + + g_assert (info->op_list); + + if (op_list == info->op_list || + meta_draw_op_list_contains (op_list, info->op_list)) + { + set_error (error, context, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Including draw_ops \"%s\" here would create a circular reference"), + name); + return; + } + + op = meta_draw_op_new (META_DRAW_TILE); + + meta_draw_op_list_ref (op_list); + op->data.tile.op_list = op_list; + op->data.tile.x = x ? optimize_expression (info->theme, x) : + g_strdup ("0"); + op->data.tile.y = y ? optimize_expression (info->theme, y) : + g_strdup ("0"); + op->data.tile.width = width ? optimize_expression (info->theme, width) : + g_strdup ("width"); + op->data.tile.height = height ? optimize_expression (info->theme, height) : + g_strdup ("height"); + op->data.tile.tile_xoffset = tile_xoffset ? + optimize_expression (info->theme, tile_xoffset) : + g_strdup ("0"); + op->data.tile.tile_yoffset = tile_yoffset ? + optimize_expression (info->theme, tile_yoffset) : + g_strdup ("0"); + op->data.tile.tile_width = optimize_expression (info->theme, tile_width); + op->data.tile.tile_height = optimize_expression (info->theme, tile_height); + + meta_draw_op_list_append (info->op_list, op); + + push_state (info, STATE_TILE); + } else { set_error (error, context, @@ -3292,6 +3417,7 @@ start_element_handler (GMarkupParseContext *context, case STATE_ICON: case STATE_TITLE: case STATE_INCLUDE: + case STATE_TILE: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a draw operation element"), element_name); @@ -3525,6 +3651,10 @@ end_element_handler (GMarkupParseContext *context, pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; + case STATE_TILE: + pop_state (info); + g_assert (peek_state (info) == STATE_DRAW_OPS); + break; case STATE_COLOR: pop_state (info); g_assert (peek_state (info) == STATE_GRADIENT); @@ -3780,6 +3910,9 @@ text_handler (GMarkupParseContext *context, case STATE_INCLUDE: NO_TEXT ("include"); break; + case STATE_TILE: + NO_TEXT ("tile"); + break; case STATE_COLOR: NO_TEXT ("color"); break; diff --git a/src/theme.c b/src/theme.c index 10090bec7..a28549268 100644 --- a/src/theme.c +++ b/src/theme.c @@ -2285,6 +2285,9 @@ meta_draw_op_new (MetaDrawType type) case META_DRAW_OP_LIST: size += sizeof (dummy.data.op_list); break; + case META_DRAW_TILE: + size += sizeof (dummy.data.tile); + break; } op = g_malloc0 (size); @@ -2400,6 +2403,7 @@ meta_draw_op_free (MetaDrawOp *op) g_free (op->data.title.x); g_free (op->data.title.y); break; + case META_DRAW_OP_LIST: if (op->data.op_list.op_list) meta_draw_op_list_unref (op->data.op_list.op_list); @@ -2408,6 +2412,19 @@ meta_draw_op_free (MetaDrawOp *op) g_free (op->data.op_list.width); g_free (op->data.op_list.height); break; + + case META_DRAW_TILE: + if (op->data.tile.op_list) + meta_draw_op_list_unref (op->data.tile.op_list); + g_free (op->data.tile.x); + g_free (op->data.tile.y); + g_free (op->data.tile.width); + g_free (op->data.tile.height); + g_free (op->data.tile.tile_xoffset); + g_free (op->data.tile.tile_yoffset); + g_free (op->data.tile.tile_width); + g_free (op->data.tile.tile_height); + break; } g_free (op); @@ -2720,7 +2737,10 @@ draw_op_as_pixbuf (const MetaDrawOp *op, break; case META_DRAW_OP_LIST: - break; + break; + + case META_DRAW_TILE: + break; } return pixbuf; @@ -3052,6 +3072,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, g_object_unref (G_OBJECT (gc)); } break; + case META_DRAW_OP_LIST: { int rx, ry, rwidth, rheight; @@ -3066,6 +3087,55 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, rx, ry, rwidth, rheight); } break; + + case META_DRAW_TILE: + { + int rx, ry, rwidth, rheight; + int tile_xoffset, tile_yoffset, tile_width, tile_height; + GdkRectangle new_clip; + int tile_x, tile_y; + + rx = parse_x_position_unchecked (op->data.tile.x, env); + ry = parse_y_position_unchecked (op->data.tile.y, env); + rwidth = parse_size_unchecked (op->data.tile.width, env); + rheight = parse_size_unchecked (op->data.tile.height, env); + + new_clip.x = rx; + new_clip.y = ry; + new_clip.width = rwidth; + new_clip.height = rheight; + + if (clip == NULL || gdk_rectangle_intersect ((GdkRectangle*)clip, &new_clip, + &new_clip)) + { + tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env); + tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env); + /* tile offset should not include x/y */ + tile_xoffset -= x; + tile_yoffset -= y; + + tile_width = parse_size_unchecked (op->data.tile.tile_width, env); + tile_height = parse_size_unchecked (op->data.tile.tile_height, env); + + tile_x = rx - tile_xoffset; + + while (tile_x < (rx + rwidth)) + { + tile_y = ry - tile_yoffset; + while (tile_y < (ry + rheight)) + { + meta_draw_op_list_draw (op->data.tile.op_list, + widget, drawable, &new_clip, info, + tile_x, tile_y, tile_width, tile_height); + + tile_y += tile_height; + } + + tile_x += tile_width; + } + } + } + break; } } @@ -3260,6 +3330,15 @@ meta_draw_op_list_contains (MetaDrawOpList *op_list, child)) return TRUE; } + else if (op_list->ops[i]->type == META_DRAW_TILE) + { + if (op_list->ops[i]->data.tile.op_list == child) + return TRUE; + + if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list, + child)) + return TRUE; + } ++i; } diff --git a/src/theme.h b/src/theme.h index 5ba1790a2..17b2b4afc 100644 --- a/src/theme.h +++ b/src/theme.h @@ -192,7 +192,9 @@ typedef enum /* App's window title */ META_DRAW_TITLE, /* a draw op list */ - META_DRAW_OP_LIST + META_DRAW_OP_LIST, + /* tiled draw op list */ + META_DRAW_TILE } MetaDrawType; struct _MetaDrawOp @@ -318,6 +320,18 @@ struct _MetaDrawOp char *width; char *height; } op_list; + + struct { + MetaDrawOpList *op_list; + char *x; + char *y; + char *width; + char *height; + char *tile_xoffset; + char *tile_yoffset; + char *tile_width; + char *tile_height; + } tile; } data; }; diff --git a/theme-format.txt b/theme-format.txt index c54033428..9cbc08ea9 100644 --- a/theme-format.txt +++ b/theme-format.txt @@ -114,8 +114,11 @@ Themes are in a simple XML-subset format. x="10" y="30" width="width / 3" height="height / 4"/> - <!-- include another draw ops list --> + <!-- include another draw ops list; has optional x/y/width/height attrs --> <include name="some_other_draw_ops"/> + <!-- tile another draw ops list; has optional + x/y/width/height/tile_xoffset/tile_yoffset --> + <tile name="some_other_draw_ops" tile_width="10" tile_height="10"/> </draw_ops> <frame_style name="normal" geometry="normal">